BZOJ4383: [POI2015]Pustynia

是个很裸的差分约束?
如果有限制x>y
可以连一条边x->y,-1
代表y<=x-1 即 x>y

注意到k个数把区间划分成了k个区间,对于每个限制,新建一个点,k个特殊的数向其连边-1,它向k个区间连边0
线段树优化建图
建好图后如果不是DAG说明有负环,无解
否则是个DAG,令f[x]表示x最大能取到的值,dp f值
如果一个固定了值的位置,他的f值< 它的值,也无解

code:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;

inline void up(int &x,const int &y){if(xinline void down(int &x,const int &y){if(x>y)x=y;}
const int maxn = 210000;
const int maxm = 210000;
const int maxk = 300005;

int n,s,m,N;
int c[maxn];
struct edge{int y,c,nex;}a[maxk*20]; int len,fir[maxn*4+maxm],in[maxn*4+maxm];
inline void ins(const int x,const int y,const int c){in[y]++;a[++len]=(edge){y,c,fir[x]};fir[x]=len;}

int To[maxn<<2],tr[maxn];
void build(const int x,const int l,const int r)
{
    up(N,x);
    if(l==r) {tr[To[x]=l]=x; return;}
    int mid=l+r>>1,lc=x<<1,rc=lc|1;
    ins(x,lc,0); ins(x,rc,0);
    build(lc,l,mid); build(rc,mid+1,r);
}
int lx,rx,now;
void link(const int x,const int l,const int r)
{
    if(rxreturn;
    if(lx<=l&&r<=rx) { ins(now,x,0); return; }
    int mid=l+r>>1,lc=x<<1,rc=lc|1;
    link(lc,l,mid); link(rc,mid+1,r);
}
int f[maxn*4+maxm];
queue<int>q;
bool solve()
{
    for(int i=1;i<=N+m;i++) 
    {
        f[i]=1e9;
        if(!in[i]) q.push(i);
    }
    while(!q.empty())
    {
        const int x=q.front(); q.pop();
        if(c[To[x]]!=-1)
        {
            if(f[x]return false;
            f[x]=c[To[x]];
        }
        for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y)
        {
            down(f[y],f[x]+a[k].c);
            in[y]--; if(!in[y]) q.push(y);
        }
    }
    for(int i=1;i<=N;i++) 
    {
        if(in[i]||f[i]<1) return false;
        if(c[To[i]]!=-1) f[i]=c[To[i]];
    }
    return true;
}

int main()
{
    memset(c,-1,sizeof c);

    scanf("%d%d%d",&n,&s,&m);
    for(int i=1;i<=s;i++)
    {
        int x,y; scanf("%d%d",&x,&y);
        c[x]=y;
    }
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int l,r,k; scanf("%d%d%d",&l,&r,&k);
        int las=l; now=N+i;
        while(k--)
        {
            int x; scanf("%d",&x); ins(tr[x],N+i,-1);
            if(las1,link(1,1,n);
            las=x+1;
        }
        if(las<=r) lx=las,rx=r,link(1,1,n);
    }
    bool flag=solve();
    if(!flag) puts("NIE");
    else
    {
        puts("TAK");
        for(int i=1;i<=n;i++) printf("%d ",f[tr[i]]);
    }

    return 0;
}

你可能感兴趣的:(Poi,BZOJ,最短路,DP,线段树)