bzoj4383(拓扑排序)
給定一個(gè)長(zhǎng)度為n的正整數(shù)序列a,每個(gè)數(shù)都在1到10^9范圍內(nèi),告訴你其中s個(gè)數(shù),并給出m條信息,每條信息包含三個(gè)數(shù)l,r,k以及接下來k個(gè)正整數(shù),表示a[l],a[l+1],...,a[r-1],a[r]里這k個(gè)數(shù)中的任意一個(gè)都比任意一個(gè)剩下的r-l+1-k個(gè)數(shù)大(嚴(yán)格大于,即沒有等號(hào))。請(qǐng)任意構(gòu)造出一組滿足條件的方案,或者判斷無解。
Solution
這個(gè)模型有點(diǎn)像差分約束系統(tǒng),但是建圖復(fù)雜度過高。
考慮到每次一個(gè)區(qū)間內(nèi)的k個(gè)數(shù)將整段序列劃分為k+1個(gè)區(qū)間,所以我們考慮用線段樹優(yōu)化這個(gè)過程,每次建一個(gè)s點(diǎn)和這k個(gè)點(diǎn)連邊,再和剩下的數(shù)所對(duì)應(yīng)的區(qū)間連邊,這樣就保證了我們建圖的復(fù)雜度。
然后題目中給的數(shù)域是1-1e9,有兩種方法,一種是從極小向大里跑,另一種是從極大往小里跑。
如果是前一種,那么我的轉(zhuǎn)移順序必須為從小到大,回顧我們的連邊,發(fā)現(xiàn)需要從一堆區(qū)間向S走,但是這一堆區(qū)間需要下面的節(jié)點(diǎn)轉(zhuǎn)移而來,所以我們?cè)诰€段樹上連邊的方式為從下往上連。
后一種反之。
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; }?
轉(zhuǎn)載于:https://www.cnblogs.com/ZH-comld/p/9828177.html
總結(jié)
以上是生活随笔為你收集整理的bzoj4383(拓扑排序)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WPF安装打印机驱动后PrintDial
- 下一篇: getDeclaredField和get