ZOJ - 4028 LIS 差分約束
阿新 • • 發佈:2018-11-29
題意:給你每個位置以該位置結尾的最長上升子序列的值,然後給你每個點的取值範圍,求可行的原序列
題解: 我們另 源點 為 (n+1)點
1. 因為對於每個a[i] 滿足 l[i] <= a[i] <= r[i] 所以 轉換為 (n+1) -a[i] <= -l[i] a[i] - (n+1) <= r[i]
2. 若i點最長上升子序列為 k 那麼他要比前面為k 的數小於等於 ,pre[k] 表示之前 該值出現的位置 則:a[i] - a[pre[k]] <= 0
3. 若i點最長上升子序列為 k,那麼他要比之前出現 k-1 位置 的數大 即:a[i] - a[pre[k - 1]] >= 1 即:a[pre[k - 1]] - a[i] <= -1
線性約束條件找好,建圖,從原點跑最短路即可
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; const int N=1e5+10; typedef long long ll; #define INF 0x7f7f7f7f struct node { int to,nex,d; }e[N*10]; int head[N],vis[N],len,pre[N]; ll dis[N]; int n,l[N],r[N],f[N]; void init() { len=0; for(int i=0;i<=n+1;i++) { head[i]=-1; dis[i]=INF; vis[i]=0; pre[i]=0; } } void add(int u,int v,int d) { e[len].to=v; e[len].d=d; e[len].nex=head[u]; head[u]=len++; } void spfa(int s) { int u,to; queue<int> q; dis[s]=0; vis[s]=1; q.push(s); while(!q.empty()) { u=q.front();q.pop(); vis[u]=0; for(int i=head[u];i!=-1;i=e[i].nex) { to=e[i].to; if(dis[to]>dis[u]+e[i].d) { dis[to]=dis[u]+e[i].d; if(!vis[to]) q.push(to),vis[to]=1; } } } } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&f[i]); init(); for(int i=1;i<=n;i++) { scanf("%d%d",&l[i],&r[i]); add(i,n+1,-l[i]); add(n+1,i,r[i]); add(i,pre[f[i]-1],-1); if(pre[f[i]]) add(pre[f[i]],i,0); pre[f[i]]=i; } spfa(n+1); for(int i=1;i<=n;i++)printf("%lld%c",dis[i]," \n"[i==n]); } return 0; }