[POI2015]bzoj 4383 Pustynia - 线段树优化建图

52 篇文章 0 订阅

每次建一个辅助点然后线段树优化建图即可,注意特判 a[i]109 a [ i ] ≤ 10 9 .

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#define gc getchar()
#define LEN 100010
#define LOG 20
#define N (LEN*LOG+400010)
#define M (N*2)
#define INF 1000000000
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct edges{
    int to,pre;
}e[M];int h[N],a[N],Log[LEN],etop,up[LEN][LOG],isf[N],d[N],t[N];queue<int> q;
inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop,d[v]++; }
inline int Add(int x,int s,int t)
{
    if(s>t) return 0;int k=Log[t-s+1];
    if(s==t) add_edge(x,up[s][0]);
    else add_edge(x,up[s][k]),add_edge(x,up[t-(1<<k)+1][k]);
    return 0;
}
inline int toposort(int n,int c=0)
{
    for(int i=1;i<=n;i++) if(!d[i]) q.push(i);
    while(!q.empty())
    {
        int x=q.front();q.pop(),t[++c]=x;
        for(int i=h[x],y;i;i=e[i].pre)
            if(!(--d[y=e[i].to])) q.push(y);
    }
    return 0;
}
int main()
{
    int n=inn(),s=inn(),m=inn(),c=n;
    for(int i=1,x;i<=s;i++) x=inn(),a[x]=inn();
//  for(int i=1;i<=n;i++) debug(i)sp,debug(a[i])ln;
    for(int i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
    for(int i=1;i<=n;i++) add_edge(up[i][0]=++c,i);
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            up[i][j]=++c,add_edge(up[i][j],up[i][j-1]),
            add_edge(up[i][j],up[i+(1<<(j-1))][j-1]);
    while(m--)
    {
        int l=inn(),r=inn(),k=inn(),las=l-1,fz=++c,x;
        while(k--) x=inn(),add_edge(x,fz),Add(fz,las+1,x-1),las=x;
        Add(fz,las+1,r),isf[fz]=1;
    }
    toposort(c);
    for(int i=1;i<=n;i++) if(d[i]) return !printf("NIE\n");
    for(int j=c,x;j;j--)
        if(a[x=t[j]])
        {
            for(int i=h[x],y;i;i=e[i].pre)
                if(a[x]<a[e[i].to]+isf[e[i].to])
                    return !printf("NIE\n");
        }
        else{
            if(x<=n) a[x]=1;
            for(int i=h[x],y;i;i=e[i].pre)
                a[x]=max(a[x],a[e[i].to]+isf[e[i].to]);
        }
    for(int i=1;i<=n;i++) if(a[i]>INF) return !printf("NIE\n");
    printf("TAK\n");
    for(int i=1;i<=n;i++) printf("%d ",a[i]);
    return !printf("\n");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值