ZOJ4028 LIS(差分约束)

图中给出了不等式关系并求可行解,考虑使用差分约束来解决。

差分约束的基本套路是:

1.找全不等关系

2.找到一个点可以遍历全图

3.对于可行解问题,跑最短路,一般上我们定义>=关系式

对于本题的关系式,为了控制l<=ai<=r,我们用一个超级点去连

对于fi的限制,有两种情况,前面有和他长度相等的,这样前一个必须大于等于后一个。

第二种是我们必须大于f[i]-1。

对于这两种情况,只需要维护一个last数组表示最靠近当前位置的每个长度的位置

为什么只需要维护这个就能找全关系呢?因为对于第一种,他是一个递减的,因此只要最靠近的大于他,前面的都大于他

对于第二种情况,因为我们只需要大于前面最小的,就能满足题意,所以也只需要找最靠近他的

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;
int h[N],ne[N],e[N],w[N],idx;
int n,f[N],l[N],r[N];
int last[N];
int st[N];
ll dis[N];
void add(int a,int b,int c){
    e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
void spfa(){
    queue<int> q;
    q.push(n+1);
    dis[n+1]=0;
    for(int i=1;i<=n+1;i++)
        st[i]=0;
    st[n+1]=1;
    while(q.size()){
        auto t=q.front();
        q.pop();
        st[t]=0;
        for(int i=h[t];i!=-1;i=ne[i]){
            int j=e[i];
            if(dis[j]>dis[t]+w[i]){
                dis[j]=dis[t]+w[i];
                if(!st[j]){
                    q.push(j);
                    st[j]=1;
                }
            }
        }
    }
    for(int i=1;i<n;i++)
        cout<<dis[i]<<" ";
    cout<<dis[n]<<endl;
}
int main(){
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--){
        cin>>n;
        int i;
        idx=0;
        for(i=0;i<=n+1;i++){
            h[i]=-1;
            last[i]=0;
            dis[i]=1e18;
        }
        for(i=1;i<=n;i++){
            cin>>f[i];
        }
        for(i=1;i<=n;i++){
            cin>>l[i]>>r[i];
        }
        for(i=1;i<=n;i++){
            add(i,n+1,-l[i]);
            add(n+1,i,r[i]);
            if(last[f[i]]){
                add(last[f[i]],i,0);
            }
            if(f[i]){
                add(i,last[f[i]-1],-1);
            }
            last[f[i]]=i;
        }
        spfa();
    }
    return 0;
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13757332.html