洛谷P3588 [POI2015]PUS(线段树优化建图)

题面

传送门

题解

先考虑暴力怎么做,我们把所有(r-l+1-k)中的点向(x)连有向边,表示(x)必须比它们大,那么如果这张图有环显然就无解了,否则的话我们跑一个多源最短路,每个点的(dis)就是它的答案

然而这里边数太多了,所以得线段树优化建边

//minamoto
#include<bits/stdc++.h>
#define R register
#define ls (p<<1)
#define rs (p<<1|1)
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
    if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]=' ';
}
const int N=5e5+5,M=1e7+5,lim=1e9;
struct eg{int v,nx,w;}e[M];int head[N],deg[N],tot;
inline void add(R int u,R int v,R int w){e[++tot]={v,head[u],w},head[u]=tot,++deg[v];}
int vis[N],dis[N],dfn[N],a[N],q[N];
int cnt,n,s,m,h,t;
void build(int p,int l,int r){
	if(l==r)return dfn[p]=l,void();
	int mid=(l+r)>>1;dfn[p]=++cnt;
	build(ls,l,mid),build(rs,mid+1,r);
	add(dfn[ls],dfn[p],0),add(dfn[rs],dfn[p],0);
}
void link(int p,int l,int r,int ql,int qr,int x){
	if(ql<=l&&qr>=r)return add(dfn[p],x,0),void();
	int mid=(l+r)>>1;
	if(ql<=mid)link(ls,l,mid,ql,qr,x);
	if(qr>mid)link(rs,mid+1,r,ql,qr,x);
}
int main(){
//	freopen("testdata.in","r",stdin);
	cnt=n=read(),s=read(),m=read();
	build(1,1,n);
	for(R int i=1,k,x;i<=s;++i)k=read(),x=read(),a[k]=dis[k]=x;
	for(R int T=1,l,r,k,las,x;T<=m;++T){
		l=read(),r=read(),k=read(),las=l-1,++cnt;
		while(k--)x=read(),add(cnt,x,1),(x>las+1)?(link(1,1,n,las+1,x-1,cnt),0):0,las=x;
		x<r?(link(1,1,n,x+1,r,cnt),0):0;
	}
	h=1,t=0;
	fp(i,1,cnt)!dis[i]?dis[i]=1:0,!deg[i]?q[++t]=i:0;
	while(h<=t){
		int u=q[h++];vis[u]=1;
		go(u)if(cmax(dis[v],dis[u]+e[i].w),!--deg[v]?q[++t]=v:0,a[v]&&dis[v]>a[v])return puts("NIE"),0;
	}
	fp(i,1,cnt)if(!vis[i]||dis[i]>lim)return puts("NIE"),0;
	puts("TAK");
	fp(i,1,n)print(dis[i]);
	return Ot(),0;
}
原文地址:https://www.cnblogs.com/bztMinamoto/p/10555370.html