#差分约束系统,最长路,线段树优化建边#洛谷 3588 [POI2015] PUS

题目

给定一个长度为\(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\) 个数大 (严格大于,即没有等号)。


分析

考虑约束条件形如\(a[x]+1<a[y]\),建边跑最长路即可,
现在问题是建边,考虑线段树优化建边,
由于它有已知值,所以要在已知值的基础上跑最长路,
如果约束条件有环那无解,最小答案超过已知值无解


代码

#include <cstdio>
#include <cctype> 
#define rr register
using namespace std;
const int N=1000011; struct node{int y,w,next;}e[N<<2];
int ls[N],rs[N],deg[N],dis[N],a[N],n,cnt,m,T,et,as[N],root,p[N],q[N],head=1,tail;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void add(int x,int y,int w){
	e[++et]=(node){y,w,as[x]},as[x]=et;
}
inline void build(int &k,int l,int r){
	if (l==r) {k=l; return;}
	if (!k) k=++cnt;
	rr int mid=(l+r)>>1;
	build(ls[k],l,mid);
	build(rs[k],mid+1,r);
    add(ls[k],k,0),add(rs[k],k,0);
}
inline void update(int k,int l,int r,int x,int y,int z){
	if (l==x&&r==y) {add(k,z,0); return;}
	rr int mid=(l+r)>>1;
	if (y<=mid) update(ls[k],l,mid,x,y,z);
	else if (x>mid) update(rs[k],mid+1,r,x,y,z);
	    else update(ls[k],l,mid,x,mid,z),update(rs[k],mid+1,r,mid+1,y,z);
}
signed main(){
	cnt=n=iut(),T=iut(),m=iut();
	for (rr int x;T;--T)
	     x=iut(),dis[x]=a[x]=iut();
	build(root,1,n);
	for (rr int i=1;i<=m;++i){
		rr int l=iut(),r=iut(); p[0]=iut();
		for (rr int j=1;j<=p[0];++j) add(cnt+i,p[j]=iut(),1);
		for (rr int j=1;j<p[0];++j) if (p[j]+1<p[j+1])
		    update(root,1,n,p[j]+1,p[j+1]-1,cnt+i);
		if (l<p[1]) update(root,1,n,l,p[1]-1,cnt+i);
		if (p[p[0]]<r) update(root,1,n,p[p[0]]+1,r,cnt+i);
	}
	cnt+=m;
	for (rr int i=1;i<=cnt;++i)
	if (!deg[i]){
		q[++tail]=i;
		if (!dis[i]) dis[i]=1;
	}
	while (head<=tail){
		rr int x=q[head++];
		for (rr int i=as[x];i;i=e[i].next)
		if (dis[e[i].y]<dis[x]+e[i].w){
			dis[e[i].y]=dis[x]+e[i].w;
			if (dis[e[i].y]>a[e[i].y]&&a[e[i].y])
			    return !printf("NIE");
			if (--deg[e[i].y]==0) q[++tail]=e[i].y;
		}
	}
	for (rr int i=1;i<=cnt;++i)
	if (deg[i]>0||dis[i]>1e9)
	    return !printf("NIE");
	printf("TAK");
	for (rr int i=1;i<=n;++i) putchar(i==1?10:32),print(dis[i]); 
	return 0;
}
posted @ 2021-07-07 11:47  lemondinosaur  阅读(39)  评论(0编辑  收藏  举报