[bzoj 4383--POI2015]Pustynia

给定一个长度为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个数大(严格大于,即没有等号)。
请任意构造出一组满足条件的方案,或者判断无解。

这道题首先运用差分约束的思想,把小的往大的连边,然后拓扑排序一下之后,再判断一下细节就可以了。对于边数过多的问题,用线段树优化建边就可以了。

#include
#include
#include
#include
#include
#include
#define inf 1000000000
using namespace std;
queue<int>q;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
inline void write(int x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
struct node
{
    int x,y,c,next;
}a[2000010];int id,len,ru[400010],last[400010];
inline void ins(int x,int y,int c)
{
    len++;ru[y]++;
    a[len].x=x;a[len].y=y;a[len].c=c;
    a[len].next=last[x];last[x]=len;
}
struct trnode
{
    int l,r,lc,rc;
}tr[200010];int trlen;
int ex[100010];
inline void bt(int l,int r)
{
    trlen++;int now=trlen;
    tr[now].l=l;tr[now].r=r;
    if(l==r)ex[l]=now;
    else
    {
        int mid=(l+r)>>1;
        tr[now].lc=trlen+1;ins(tr[now].lc,now,0),bt(l,mid);
        tr[now].rc=trlen+1;ins(tr[now].rc,now,0),bt(mid+1,r);
    }
}
inline void Link(int now,int l,int r)
{
    if(l>r)return ;
    if(tr[now].l==l && tr[now].r==r){ins(now,id,1);return ;}
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
    if(r<=mid)Link(lc,l,r);
    else if(mid+1<=l)Link(rc,l,r);
    else Link(lc,l,mid),Link(rc,mid+1,r);
}
int f[400010],ul[400010];
int main()
{
    //freopen("a.in","r",stdin);
    //freopen("a.out","w",stdout);
    int n=read(),cnt=read(),m=read();bt(1,n),id=trlen;
    for(int i=1;i<=cnt;i++){int p=read(),d=read();f[ex[p]]=d,ul[ex[p]]=d;}
    for(int i=1;i<=m;i++)
    {
        id++;int l=read(),r=read(),k=read(),lt=l;
        for(int j=1;j<=k;j++){int p=read();ins(id,ex[p],0),Link(1,lt,p-1);lt=p+1;}
        Link(1,lt,r);
    }
    for(int i=1;i<=id;i++)if(!ru[i]){q.push(i);if(!f[i])f[i]=1;}
    while(q.empty()!=true)
    {
        int x=q.front();q.pop();
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            f[y]=max(f[y],f[x]+a[k].c);
            ru[y]--;if(ru[y]==0)q.push(y);
        }
    }
    bool bk=true;
    for(int i=1;i<=id;i++)if(f[i]<1 || f[i]>inf || ru[i] || (f[i]>ul[i] && ul[i])){bk=false;break;}
    if(bk==false)printf("NIE\n");
    else
    {
        printf("TAK\n");
        for(int i=1;i<=n;i++)printf("%d ",f[ex[i]]);
    }
    return 0;
}

你可能感兴趣的:(bzoj,Poi,线段树,拓扑排序,bzoj600步)