bzoj4383(拓扑排序)
生活随笔
收集整理的這篇文章主要介紹了
bzoj4383(拓扑排序)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
給定一個長度為n的正整數序列a,每個數都在1到10^9范圍內,告訴你其中s個數,并給出m條信息,每條信息包含三個數l,r,k以及接下來k個正整數,表示a[l],a[l+1],...,a[r-1],a[r]里這k個數中的任意一個都比任意一個剩下的r-l+1-k個數大(嚴格大于,即沒有等號)。請任意構造出一組滿足條件的方案,或者判斷無解。
Solution
這個模型有點像差分約束系統,但是建圖復雜度過高。
考慮到每次一個區間內的k個數將整段序列劃分為k+1個區間,所以我們考慮用線段樹優化這個過程,每次建一個s點和這k個點連邊,再和剩下的數所對應的區間連邊,這樣就保證了我們建圖的復雜度。
然后題目中給的數域是1-1e9,有兩種方法,一種是從極小向大里跑,另一種是從極大往小里跑。
如果是前一種,那么我的轉移順序必須為從小到大,回顧我們的連邊,發現需要從一堆區間向S走,但是這一堆區間需要下面的節點轉移而來,所以我們在線段樹上連邊的方式為從下往上連。
后一種反之。
Code
#include<iostream> #include<cstdio> #include<queue> #include<cstring> #define N 400002 #define M 4000003 using namespace std; queue<int>q; int head[N],tot,du[N],ji[N],anti_ji[N],top,rs[N],ls[N],s,n,m,pos,ss,x,a[N],l,r,k,num[N],tag; struct node{int n,to,l; }e[M]; inline void add(int u,int v,int l){e[++tot].n=head[u];e[tot].to=v;e[tot].l=l;du[v]++;head[u]=tot; } void build(int cnt,int l,int r){if(l==r){ji[l]=cnt;anti_ji[cnt]=l;return;}int mid=(l+r)>>1;ls[cnt]=++top;rs[cnt]=++top;add(ls[cnt],cnt,0);add(rs[cnt],cnt,0);build(ls[cnt],l,mid);build(rs[cnt],mid+1,r); } void query(int cnt,int l,int r,int L,int R){if(l>=L&&r<=R){add(cnt,s,0);return;}int mid=(l+r)>>1;if(mid>=L)query(ls[cnt],l,mid,L,R);if(mid<R)query(rs[cnt],mid+1,r,L,R); } int main(){top=1;scanf("%d%d%d",&n,&ss,&m);for(int i=1;i<=ss;++i)scanf("%d%d",&pos,&x),a[pos]=x;build(1,1,n);for(int i=1;i<=m;++i){scanf("%d%d%d",&l,&r,&k);int p=l;s=++top;for(int j=1;j<=k;++j){scanf("%d",&x);add(s,ji[x],1);if(x>p)query(1,1,n,p,x-1);p=x+1;}if(p<=r)query(1,1,n,p,r);}for(int i=1;i<=top;++i){if(!du[i])q.push(i),num[i]=1;if(a[anti_ji[i]])num[i]=a[anti_ji[i]];}while(!q.empty()){int u=q.front();q.pop();for(int i=head[u];i;i=e[i].n){int v=e[i].to,x=num[u]+e[i].l;if(!--du[v])q.push(v);if(!a[anti_ji[v]]){num[v]=max(num[v],x);}else{num[v]=a[anti_ji[v]];if(a[anti_ji[v]]<x)tag=1;}}}for(int i=1;i<=top;++i)if(du[i])tag=1;for(int i=1;i<=n;++i)if(num[ji[i]]>1e9||!num[ji[i]])tag=1;if(tag){printf("NIE\n");return 0;}printf("TAK\n");for(int i=1;i<=n;++i)printf("%d ",num[ji[i]]);return 0; }Code2
#include<iostream> #include<cstdio> #include<queue> #define N 400002 #define M 4000003 using namespace std; queue<int>q; int head[N],tot,du[N],ji[N],anti_ji[N],top,rs[N],ls[N],s,n,m,pos,ss,x,a[N],l,r,k,num[N],tag; struct node{int n,to,l; }e[M]; inline void add(int u,int v,int l){e[++tot].n=head[u];e[tot].to=v;e[tot].l=l;du[v]++;head[u]=tot; } void build(int cnt,int l,int r){if(l==r){ji[l]=cnt;anti_ji[cnt]=l;return;}int mid=(l+r)>>1;ls[cnt]=++top;rs[cnt]=++top;add(cnt,ls[cnt],0);add(cnt,rs[cnt,0);build(ls[cnt],l,mid);build(rs[cnt],mid+1,r); } void query(int cnt,int l,int r,int L,int R){if(l>=L&&r<=R){add(s,cnt,0);return;}int mid=(l+r)>>1;if(mid>=L)query(ls[cnt],l,mid,L,R);if(mid<R)query(rs[cnt],mid+1,r,L,R); } int main(){top=1;scanf("%d%d%d",&n,&ss,&m);for(int i=1;i<=ss;++i)scanf("%d%d",&pos,&x),a[pos]=x;build(1,1,n);for(int i=1;i<=m;++i){scanf("%d%d%d",&l,&r,&k);int p=l;s=++top;for(int j=1;j<=k;++j){scanf("%d",&x);add(ji[x],s,1);if(x>p)query(1,1,n,p,x-1);p=x+1;}if(p<=r)query(1,1,n,p,r);}for(int i=1;i<=top;++i){if(!du[i])q.push(i);num[i]=1e9;}while(!q.empty()){int u=q.front();q.pop();if(anti_ji[u]&&!num[u])num[u]=1e9;for(int i=head[u];i;i=e[i].n){int v=e[i].to,x=num[u]-e[i].l;if(!--du[v])q.push(v);if(!a[anti_ji[v]]){num[v]=min(num[v],x);}else{num[v]=a[anti_ji[v]];if(a[anti_ji[v]]>x)tag=1;}}}for(int i=1;i<=top;++i)if(du[i])tag=1;if(tag){printf("NIE\n");return 0;}printf("TAK\n");for(int i=1;i<=n;++i)printf("%d ",num[ji[i]]);return 0; }?
轉載于:https://www.cnblogs.com/ZH-comld/p/9828177.html
總結
以上是生活随笔為你收集整理的bzoj4383(拓扑排序)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WPF安装打印机驱动后PrintDial
- 下一篇: getDeclaredField和get