洛谷P3588 线段树优化建图

版权声明: https://blog.csdn.net/DancingZ/article/details/82805714

题目描述

给定一个长度为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;
}

猜你喜欢

转载自blog.csdn.net/DancingZ/article/details/82805714
今日推荐