1. 程式人生 > >洛谷P3588 線段樹優化建圖

洛谷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;
}