1. 程式人生 > >bzoj4383 [POI2015]Pustynia(線段樹優化建圖+拓撲序dp)

bzoj4383 [POI2015]Pustynia(線段樹優化建圖+拓撲序dp)

首先我們有樸素的想法,直接建圖拓撲序,倒著dp求每個點的最小值即可。
然而這樣建邊可能是O(n2)
我們考慮對於一條資訊,我們新建一個節點p,大於的點我們向p連一條邊權為1的邊,小於的點p向它連一條邊權為0的邊。這樣就好多了,然而最壞還是O(n2)的囧

我們考慮k個大於的點把一個區間分成了至多k+1個區間,這k+1個連續的區間我們可以用線段樹優化到O(logn)個點。

因此我們線段樹優化建圖即可。點數O(2n+m),邊數O(klogn+k+2n)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue> using namespace std; #define ll long long #define inf 0x3f3f3f3f #define N 100010 inline char gc(){ static char buf[1<<16],*S,*T; if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;} return *S++; } inline int read(){ int x=0,f=1;char ch=gc(); while
(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();} while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc(); return x*f; } int n,tot=0,m,h[N<<2],num=0,a[N<<2],f[N<<2],du[N<<2],rt=0,pos[N],q[N<<2]; struct edge{ int to,next,val; }data[6200000]; inline void add(int x,int y,int
val){ data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].val=val;du[y]++; } struct node{ int lc,rc; }tr[N<<2]; inline void build(int &p,int l,int r){ p=++tot;if(l==r){pos[l]=p;return;}int mid=l+r>>1; build(tr[p].lc,l,mid);build(tr[p].rc,mid+1,r); add(p,tr[p].lc,0);add(p,tr[p].rc,0); } inline void cover(int p,int l,int r,int x,int y){ if(x>y) return;if(x<=l&&r<=y){add(tot,p,0);return;} int mid=l+r>>1; if(x<=mid) cover(tr[p].lc,l,mid,x,y); if(y>mid) cover(tr[p].rc,mid+1,r,x,y); } int main(){ // freopen("a.in","r",stdin); n=read();build(rt,1,n);int owo=read();m=read(); while(owo--){int x=read();a[pos[x]]=read();} while(m--){ int x=read(),y=read();owo=read();++tot; while(owo--){int z=read();add(pos[z],tot,1);cover(rt,1,n,x,z-1);x=z+1;} cover(rt,1,n,x,y); }int qh=1,qt=0; for(int i=1;i<=tot;++i) if(!du[i]) q[++qt]=i; while(qh<=qt){ int x=q[qh++]; for(int i=h[x];i;i=data[i].next){ int y=data[i].to;if(--du[y]==0) q[++qt]=y; } }if(qt!=tot){puts("NIE");return 0;} for(int ii=tot;ii>=1;--ii){ int x=q[ii]; for(int i=h[x];i;i=data[i].next){ int y=data[i].to;f[x]=max(f[x],f[y]+data[i].val); }if(!f[x]) f[x]=1; if(a[x]&&f[x]>a[x]||f[x]>1e9){puts("NIE");return 0;} if(a[x]) f[x]=a[x]; }puts("TAK"); for(int i=1;i<=n;++i) printf("%d ",f[pos[i]]); return 0; }