逃离地球的博客

Intervals 题解

2020-02-24 · 5 min read
题解

题目链接

本蒟蒻最近在复习图论,听机房里的大佬说这道题是一道差分约束裸题,就跑过来做了这道题。

简单介绍一下差分约束系统:差分约束系统就是给出n个变量 xix_{i},在m个形如 xixjckx_{i}-x_{j}\le c_{k} 的不等式的约束下,求解所有满足这些不等式的解。

而查分约束系统可以通过图论解决。我们可以把每一个变量看做一个节点,而每个约束条件 xixjckx_{i}-x_{j}\le c_{k} 可以视为 jj 节点到 ii 节点连了一条权值为ckc_{k}的有向边。

在这个图中,节点ii到节点 jj 的最短路为 xixjx_{i}-x_{j} 的最大值,因为对于单源最短路径满足的三角不等式 disuw(u,v)+disvdis_{u}\le w(u,v)+dis_{v},在本图中为 disick+disjdis_{i}\le c_{k}+dis_{j},变形可得 disidisjckdis_{i}-dis_{j}\le c_{k},即节点 ii 到节点 jj 的最短路为 xixjx_{i}-x_{j} 的最大值。

再看这道题,要在区间 [aia_{i}bib_{i}] 中至少取任意互不相同的 cic_{i} 个整数。我们不妨设p[k]为0到k之间选几个整数。由题意易得,p[bi]p[ai]cip[b_{i}]-p[a_{i}]\ge c_{i},而题意中又有一些隐藏条件:

  1. p[i]p[i1]0p[i]-p[i-1]\ge0,即 00kk 中选出的数肯定大于等于 00k1k-1中选出的数
  2. p[k1]p[k]1p[k-1]-p[k]\ge-1,即每个数至多选一次。

我们还需要建立一个根节点,与所有节点相连且边权为0,这样就可以以根节点为出发点跑一个最短/长路了。

得到这些条件后,就可以建一个图,然后跑一遍从根节点出发的最长路(因为要求最小值),再输出dis[max]dis[max]就可以了。

#include<bits/stdc++.h>
using namespace std;
int tot=0,dis[500003];
struct node{
    int v,k;
};
vector<node>head[500003];//邻接表

inline int read(){
    int s=0,g=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            g=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+(ch^48);
        ch=getchar();
    }
    return s*g;
}
int max(int a,int b){
    if(a>b)
        return a;
    return b;
}

void spfa(int start){//spfa求最长路
    bool vis[500003];
    queue<int> que;
    que.push(start);
    for(int i=0;i<=tot;i++){
    	dis[i]=-0x7fffffff;
    	vis[i]=false;
    }
    vis[start]=true;
    dis[start]=0;

    while(!que.empty()){
        int num=que.front();
        que.pop();
        vis[num]=false;
        for(int i=0;i<head[num].size();i++){
            if(dis[head[num][i].v]<dis[num]+head[num][i].k){
                dis[head[num][i].v]=dis[num]+head[num][i].k;
                if(!vis[head[num][i].v]){
                	que.push(head[num][i].v);
                	vis[head[num][i].v]=true;
                }
            }
        }
    }
}

int main(){
    int n,a,b,c,t;
    node p;
    t=read();
    while(t){
        n=read();
    	for(int i=0;i<=50002;i++){
    		vector<node>().swap(head[i]);
        }//清空向量
        tot=0;

    	for(int i=0;i<n;i++){
            a=read(),b=read(),c=read();
            p.v=b;
            p.k=c;
            head[a-1].push_back(p);
            tot=max(b,tot);
        }//建图

        for(int i=1;i<=tot;i++){
            p.k=-1;
            p.v=i-1;
            head[i].push_back(p);//隐藏条件2

            p.k=0;
            p.v=i;
            head[i-1].push_back(p);//隐藏条件1

			head[50002].push_back(p);//我设50002号节点为根节点,连上所有节点
        }
        p.k=0;
        p.v=0;
        head[50002].push_back(p);
        spfa(50002);//spfa不是死了吗
        printf("%d\n",dis[tot]);
        if(--t)
        	cout<<endl;//注意这里的输出格式,特别坑,我wa了好多次才发现
    }
    return 0;
}
本站总访问量