【bzoj4383】[POI2015]Pustynia【拓扑排序】【线段树优化建图】

其实就是一些大小关系。我们设一条边 uv u → v 代表 u>v u > v 或者 uv u ≤ v ,这要看具体情况,或者说分两类。对于每个限制,我们可以开一个虚点,每个大的向虚点连一条 的边,然后发现虚点会向若干段连续区间连边,直接线段树优化连边就好了。最后填数时,倒过来贪心,深度越深,就贪心取越小。其实这就是一个DAG上的dp。
在xsy过了,在lydsy上因常数过大TLE了。。。

#include
#include
#include
#include
#include
#pragma GCC optimize(3)
using namespace std;
const int N=100005,M=1000005;
int n,s,m,p,d,l,r,k,cnt,tot,rt,x[N],f[M],ch[M][2],in[M],pos[M];
bool vis[M],ck[M];
queue<int> q;
vector<int> e1[M],e2[M];
void adde(int u,int v){
    e1[u].push_back(v);
    in[v]++;
    e2[v].push_back(u);
}
void build(int &o,int l,int r){
    o=++tot;
    if(l==r){
        adde(o,l);
        return;
    }
    int mid=(l+r)/2;
    build(ch[o][0],l,mid);
    build(ch[o][1],mid+1,r);
    adde(o,ch[o][0]);
    adde(o,ch[o][1]);
}
void update(int o,int l,int r,int L,int R,int v){
    if(L<=l&&R>=r){
        adde(v,o);
        return;
    }
    int mid=(l+r)/2;
    if(L<=mid){
        update(ch[o][0],l,mid,L,R,v);
    }
    if(R>mid){
        update(ch[o][1],mid+1,r,L,R,v);
    }
}
int main(){
    scanf("%d%d%d",&n,&s,&m);
    for(int i=1;i<=s;i++){
        scanf("%d%d",&p,&d);
        f[p]=d;
        ck[p]=true;
    }
    tot=n;
    build(rt,1,n);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&l,&r,&k);
        tot++;
        for(int j=1,last=l-1;j<=k;last=x[j],j++){
            scanf("%d",&x[j]);
            adde(x[j],tot);
            if(last+11,n,last+1,x[j]-1,tot);
            }
        }
        if(x[k]1,n,x[k]+1,r,tot);
        }
    }
    for(int i=1;i<=tot;i++){
        if(!in[i]){
            q.push(i);
        }
    }
    while(!q.empty()){
        int u=q.front(),v;
        q.pop();
        pos[++pos[0]]=u;
        vis[u]=true;
        for(int i=0;i<(int)e1[u].size();i++){
            v=e1[u][i];
            in[v]--;
            if(!in[v]){
                q.push(v);
            }
        }
    }
    for(int i=pos[0];i>=1;i--){
        if(!f[pos[i]]){
            f[pos[i]]=1;
        }
        for(int j=0;j<(int)e2[pos[i]].size();j++){
            int v=e2[pos[i]][j];
            if(pos[i]<=n){
                if(ck[v]){
                    if(f[pos[i]]+1>f[v]){
                        puts("NIE");
                        return 0;
                    }
                }else{
                    f[v]=max(f[v],f[pos[i]]+1);
                }
            }else{
                if(ck[v]){
                    if(f[pos[i]]>f[v]){
                        puts("NIE");
                        return 0;
                    }
                }else{
                    f[v]=max(f[v],f[pos[i]]);
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        if(!vis[i]||f[i]>1000000000||f[i]<1){
            puts("NIE");
            return 0;
        }
    }
    puts("TAK");
    for(int i=1;i<=n;i++){
        printf("%d ",f[i]);
    }
    puts("");
    return 0;
}

你可能感兴趣的:(拓扑排序,线段树优化建图)