图中给出了不等式关系并求可行解,考虑使用差分约束来解决。
差分约束的基本套路是:
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