洛谷P3588 線段樹優化建圖
題目描述
給定一個長度為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個數大(嚴格大於,即沒有等號)。請任意構造出一組滿足條件的方案,或者判斷無解。
輸入輸出格式
輸入格式:
第一行包含三個正整數n,s,m(1<=s<=n<=100000,1<=m<=200000)。接下來s行,每行包含兩個正整數p[i],di,表示已知a[p[i]]=d[i],保證p[i]遞增。接下來m行,每行一開始為三個正整數l[i],r[i],k[i](1<=l[i]<r[i]<=n,1<=k[i]<=r[i]-l[i]),接下來k[i]個正整數x[1],x[2],...,x[k[i]](l[i]<=x[1]<x[2]<...<x[k[i]]<=r[i]),表示這k[i]個數中的任意一個都比任意一個剩下的r[i]-l[i]+1-k[i]個數大。Σk <= 300,000
輸出格式:
若無解,則輸出NIE。否則第一行輸出TAK,第二行輸出n個正整數,依次輸出序列a中每個數。
輸入輸出樣例
輸入樣例#1: 複製
5 2 2
2 7
5 3
1 4 2 2 3
4 5 1 4
輸出樣例#1: 複製
TAK
6 7 1000000000 6 3
說明
給定一個長度為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個數大(嚴格大於,即沒有等號)。
請任意構造出一組滿足條件的方案,或者判斷無解。
線段樹建圖優化模板,首先運用差分約束的思想,如果存在環則無解。因此可行解一定是個DAG,然後就是連邊亂搞,發現強行亂搞是n^2,於是我們就要加優化。又發現一段連續的區間如果都連一條邊十分浪費,又因為是連續的區間,想到用線段樹去優化。
至於線段樹中兒子連父親還是父親連兒子,視寫法而定(我感覺挺玄乎的)。
#include<bits/stdc++.h> using namespace std; const int Maxn=100000*log2(100000); int n,s,m,v[Maxn],f[Maxn],d[Maxn],x[Maxn]; int tot,p[Maxn]; bool vst[Maxn]; struct Edge{ int cnt,h[Maxn],w[Maxn*2],to[Maxn*2],next[Maxn*2]; inline void add(int x,int y,int z){ next[++cnt]=h[x];to[cnt]=y;w[cnt]=z;h[x]=cnt;++d[y]; } }e; #define to e.to[p] struct SegMent{ struct tree{ int ls,rs,l,r; }t[Maxn*2];int root; inline void link(int x,int l,int r,int y){ // cout<<l<<" "<<r<<"\n"; if(t[x].l>r||t[x].r<l)return ; if(l<=t[x].l&&t[x].r<=r){ // cout<<x<<" "<<y<<"\n"; return e.add(y,x,0),void(); } link(t[x].ls,l,r,y),link(t[x].rs,l,r,y); } inline void build(int &x,int l,int r){ t[x=++tot]=(tree){0,0,l,r}; int mid=l+r>>1; if(l==r)return p[mid]=x,void(); build(t[x].ls,l,mid),build(t[x].rs,mid+1,r); e.add(x,t[x].ls,0),e.add(x,t[x].rs,0); } }seg; inline bool topsort(){ queue<int>Q; for(int i=1;i<=tot;++i)f[i]=v[i]?v[i]:1e9; for(int i=1;i<=tot;++i)if(!d[i])Q.push(i); while(!Q.empty()){ int x=Q.front();Q.pop(); if(f[x]<v[x])return 0; vst[x]=1; for(int p=e.h[x];p;p=e.next[p]){ // cout<<to<<"\n"; f[to]=min(f[to],f[x]+e.w[p]); if(--d[to]==0)Q.push(to); } } for(int i=1;i<=tot;++i)if(!vst[i])return 0; return 1; } int main(){ scanf("%d%d%d",&n,&s,&m); seg.build(seg.root,1,n); // memset(v,63,sizeof(v)); for(int i=1;i<=s;++i){ int x,k;scanf("%d%d",&x,&k); v[p[x]]=k; } for(int i=1;i<=m;++i){ int l,r,k;scanf("%d%d%d",&l,&r,&k); ++tot;for(int j=1;j<=k;++j){ scanf("%d",&x[j]); e.add(p[x[j]],tot,-1); } x[0]=l-1;x[k+1]=r+1; for(int j=0;j<=k;++j){ seg.link(seg.root,x[j]+1,x[j+1]-1,tot); } } if(!topsort())puts("NIE"); else { puts("TAK"); for(int i=1;i<=n;++i)cout<<f[p[i]]<<" "; } return 0; }