2018.01.15【NOIP训练】节目(支配树)(主席树优化建图)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/86499673

传送门


解析:

首先这个是一个连通性问题,显然考虑建图。

然后这个限制是形如区间的形式,考虑线段树优化建图。

然而这个限制略显窒息,因为有两维啊,一维时间一维权值,考虑以时间为根,权值为关键字建主席树。

由于是前面的可以通向后面,考虑从后往前可持久化,对应节点从前往后连有向边。

显然这样子建出来的图的连通性和原图是相同的。

然后这个询问,显然就是支配树路径上实节点的个数啊。

求出支配树后从 1 1 开始 d f s dfs 一下,同时更新路径上实节点个数就好了。

当然空间复杂度有点可怕。。。不过 n n 5 e 4 5e4 虚什么

tips:
由于显然是 D A G DAG 可以直接用搜索树上倍增求 L C A LCA 来构建支配树,毕竟 t a r j a n tarjan 算法常数略大(虽然我还是写了 t a r j a n tarjan )。。。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc put_char
#define puts put_s
#define cs const

namespace IO{
	namespace IOONLY{
		cs int Rlen=1<<18|1;
		char buf[Rlen],*p1,*p2;
		char obuf[Rlen],*p3=obuf;
	}
	inline char get_char(){
		using namespace IOONLY;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	inline void put_char(char c){
		using namespace IOONLY;
		*p3++=c;
		if(p3==obuf+Rlen)fwrite(obuf,1,Rlen,stdout),p3=obuf;
	}
	inline void put_s(cs char *s){
		for(;*s;++s)pc(*s);pc('\n');
	}
	inline void FLUSH(){
		using namespace IOONLY;
		fwrite(obuf,1,p3-obuf,stdout),p3=obuf;
	}
	
	inline int getint(){
		re int num;
		re char c;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	inline void outint(int a){
		static char ch[23];
		if(a==0)pc('0');
		while(a)ch[++ch[0]]=a-a/10*10,a/=10;
		while(ch[0])pc(ch[ch[0]--]^48);
	}
}
using namespace IO;

cs int N=50004,logN=18,M=N*logN;

struct graph{
	vector<int> edge[M];
	inline void addedge(int u,int v){edge[u].push_back(v);}
}g,revg,ng,dt;

inline void addedge(int u,int v){
	g.addedge(u,v);
	revg.addedge(v,u);
}

int n,a[N],l[N],r[N],rt[N];
int son[M][2],tot;

void build(int k,int l,int r,cs int &ql,cs int &qr,cs int &u){
	if(k==0)return ;
	if(ql<=l&&r<=qr)return addedge(u,k+n);
	int mid=(l+r)>>1;
	if(ql<=mid)build(son[k][0],l,mid,ql,qr,u);
	if(mid<qr)build(son[k][1],mid+1,r,ql,qr,u);
}

void ins(int old,int &now,int l,int r,cs int &val,cs int &u){
	now=++tot;
	son[now][0]=son[old][0];
	son[now][1]=son[old][1];
	if(old)addedge(now+n,old+n);
	addedge(now+n,u);
	if(l==r)return ;
	int mid=(l+r)>>1;
	if(val<=mid)ins(son[old][0],son[now][0],l,mid,val,u);
	else ins(son[old][1],son[now][1],mid+1,r,val,u);
}

int dfn[M],id[M],fa[M],dfs_clock;
void dfs(int u){
	id[dfn[u]=++dfs_clock]=u;
	for(int re e=0,v;e<g.edge[u].size();++e){
		v=g.edge[u][e];
		if(dfn[v])continue;
		fa[v]=u,dfs(v);
	}
}

int bel[M],val[M],semi[M],idom[M];

inline int getfa(int x){
	if(bel[x]==x)return x;
	int tmp=getfa(bel[x]);
	if(dfn[semi[val[bel[x]]]]<dfn[semi[val[x]]])val[x]=val[bel[x]];
	return bel[x]=tmp;
}

inline void tarjan(){
	for(int re i=dfs_clock;i>1;--i){
		int u=id[i];
		for(int re e=0,v;e<revg.edge[u].size();++e){
			v=revg.edge[u][e];
			if(!dfn[v])continue;
			getfa(v);
			if(dfn[semi[val[v]]]<dfn[semi[u]])semi[u]=semi[val[v]];
		}
		ng.addedge(semi[u],u);
		bel[u]=fa[u];
		u=fa[u]; 
		for(int re e=0,v;e<ng.edge[u].size();++e){
			v=ng.edge[u][e];
			getfa(v);
			if(semi[val[v]]==u)idom[v]=u;
			else idom[v]=val[v];
		}
	}
	for(int re i=2;i<=dfs_clock;++i){
		int u=id[i];
		if(idom[u]!=semi[u])idom[u]=idom[idom[u]];
	}
}


int dep[M];

void dfs_ans(int u){
	if(u<=n)++dep[u];
	for(int re e=0,v;e<dt.edge[u].size();++e){
		v=dt.edge[u][e];
		dep[v]=dep[u];
		dfs_ans(v);
	}
}

signed main(){
	n=getint();
	for(int re i=1;i<=n;++i)a[i]=getint();
	for(int re i=1;i<=n;++i)l[i]=getint(),r[i]=getint();
	for(int re i=n;i;--i)
	build(rt[i+1],1,n,l[i],r[i],i),ins(rt[i+1],rt[i],1,n,a[i],i);
	for(int re i=1;i<=tot+n;++i)semi[i]=bel[i]=val[i]=i;
	dfs(1);
	tarjan();
	for(int re i=2;i<=tot+n;++i)dt.addedge(idom[i],i);
	dfs_ans(1);
	for(int re i=1;i<=n;++i)dep[i]?outint(dep[i]),pc('\n'):puts("-1");
	FLUSH();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/86499673