差分约束 - Intervals - POJ 1201

差分约束 - Intervals - POJ 1201

题意:

给 定 n 个 区 间 [ a i , b i ] 和 n 个 整 数 c i 。 给定 n 个区间 [a_i,b_i]和 n 个整数 c_i。 n[ai,bi]nci

你 需 要 构 造 一 个 整 数 集 合 Z , 使 得 ∀ i ∈ [ 1 , n ] , Z 中 满 足 a i ≤ x ≤ b i 的 整 数 x 不 少 于 c i 个 。 你需要构造一个整数集合 Z,使得∀i∈[1,n],Z 中满足a_i≤x≤b_i的整数 x 不少于 c_i 个。 Z使i[1,n],Zaixbixci

求 这 样 的 整 数 集 合 Z 最 少 包 含 多 少 个 数 。 求这样的整数集合 Z 最少包含多少个数。 Z

输入格式

第 一 行 包 含 整 数 n 。 第一行包含整数 n。 n

接 下 来 n 行 , 每 行 包 含 三 个 整 数 a i , b i , c i 。 接下来n行,每行包含三个整数a_i,b_i,c_i。 nai,bi,ci

输出格式

输 出 一 个 整 数 表 示 结 果 。 输出一个整数表示结果。

数据范围

1 ≤ n ≤ 50000 , 0 ≤ a i , b i ≤ 50000 , 1 ≤ c i ≤ b i − a i + 1 1≤n≤50000, 0≤a_i,b_i≤50000, 1≤c_i≤b_i−a_i+1 1n50000,0ai,bi50000,1cibiai+1

Sample Input

5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

Sample Output

6

分析:

本 题 是 求 最 小 值 , 故 跑 最 长 路 。 本题是求最小值,故跑最长路。

在 某 段 区 间 中 计 数 , 考 虑 前 缀 和 的 思 想 。 在某段区间中计数,考虑前缀和的思想。

S i 表 示 大 小 介 于 区 间 [ 0 , i ] 的 数 的 个 数 。 S_i表示大小介于区间[0,i]的数的个数。 Si[0,i]

则 介 于 区 间 [ a , b ] 的 数 的 个 数 为 S b − S a − 1 。 则介于区间[a,b]的数的个数为S_b-S_{a-1}。 [a,b]SbSa1

有 约 数 不 等 式 组 : 有约数不等式组:

{ 0 ≤ S i − S i − 1 ≤ 1 , 即 第 i 个 数 选 或 不 选 < = > S i ≥ S i − 1 和 S i − 1 ≥ S i − 1 , ① S b i − S a i − 1 ≥ c i , 即 区 间 [ a i , b i ] 中 数 的 个 数 不 少 于 c i 个 < = > S b i ≥ S a i − 1 + c i ② \begin{cases}0≤S_i-S_{i-1}≤1,即第i个数选或不选\quad<=>\quad S_i≥S_{i-1}和S_{i-1}≥S_i-1,\qquad\quad①\\\\S_{b_i}-S_{a_{i}-1}≥c_i,即区间[a_i,b_i]中数的个数不少于c_i个\quad<=>\quad S_{b_i}≥S_{a_i-1}+c_i\quad②\end{cases} 0SiSi11i<=>SiSi1Si1Si1,SbiSai1ci[ai,bi]ci<=>SbiSai1+ci

由 约 束 条 件 ① , 我 们 需 要 建 立 i − 1 − > i 的 边 , 由约束条件①,我们需要建立i-1->i的边, i1>i

这 样 , 我 们 以 编 号 最 小 的 点 作 为 源 点 , 就 能 够 遍 历 到 剩 下 所 有 的 点 和 边 。 这样,我们以编号最小的点作为源点,就能够遍历到剩下所有的点和边。

为 了 便 于 前 缀 和 的 使 用 , 我 们 将 区 间 整 体 向 右 平 移 一 个 单 位 , 再 把 0 号 点 作 为 源 点 , 跑 最 长 路 即 可 。 为了便于前缀和的使用,我们将区间整体向右平移一个单位,再把0号点作为源点,跑最长路即可。 便使0

a i 和 b i 的 范 围 在 [ 1 , 50001 ] 之 间 , 最 后 我 们 输 出 d i s [ 50001 ] 即 答 案 。 a_i和b_i的范围在[1,50001]之间,最后我们输出dis[50001]即答案。 aibi[1,50001]dis[50001]

代码:

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>

using namespace std;

const int N=50010, M=150010;

int n;
int e[M],ne[M],w[M],h[N],idx;
int dis[N];
bool st[N];

void add(int a,int b,int c)
{
    e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}

void spfa()
{
    memset(dis,-0x3f,sizeof dis);
    memset(st,false,sizeof st);
    
    queue<int> Q;
    Q.push(0);
    st[0]=true;
    dis[0]=0;
    
    while(Q.size())
    {
        int u=Q.front();
        Q.pop();
        st[u]=false;
        
        for(int i=h[u];~i;i=ne[i])
        {
            int j=e[i];
            if(dis[j]<dis[u]+w[i])
            {
                dis[j]=dis[u]+w[i];
                if(!st[j])
                {
                    st[j]=true;
                    Q.push(j);
                }
            }
        }
    }
}

int main()
{
    scanf("%d",&n);
    
    memset(h,-1,sizeof h);
    for(int i=1;i<=50001;i++) add(i-1,i,0),add(i,i-1,-1);
    
    int a,b,c;
    for(int i=0;i<n;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        a++,b++;
        add(a-1,b,c);
    }
    
    spfa();
    
    printf("%d\n",dis[50001]);
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值