【线段树】【DFN】 two

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/86129199

题意:

在这里插入图片描述


分析:

翻译一下题意:给出两个N个点的树,首先选择A树中的一条边删除,然后将所有包含此边的路径u->v(要求u,v在B树中是相邻的),对应的B树中的边(u,v)删除。

由于扯到了子树,显然可以考虑DFN的方法。
很明显,路径包含关系在DFN中表示为:对于一条边(u,v),假设深度 d e e p u = d e e p v + 1 deep_u=deep_v+1
那么所有包含此边的路径必然满足:
l u d f n a r u d f n b d f n a l u d f n b r u l_u\leq dfn_a\leq r_u \leq dfn_b或dfn_a\leq l_u\leq dfn_b\leq r_u
l u ( = d f n u ) l_u(=dfn_u) 表示进入这个节点时的dfn位置。
r u r_u 表示离开这个节点的dfn位置。

由于每条边最多删除一次,所以有种很直观的方法是:维护当前状况下,是否存在要删除的边,如果有,就暴力找到它并删除。这样就可以巧妙地避免维护哪些边要被删除的信息。

接下来的操作就很简单了:对于B中的每条边,在其两个端点在A树的DFN序的位置,分别插入另一个端点。对A中的边也对应地操作。

然后就是维护区间最小&最大值,每次删除一条边时 ( u , v ) ( d e e p u = d e e p v + 1 ) (u,v),(deep_u=deep_v+1) ,在 [ l u , r u ] [l_u,r_u] 中,找到区间最小&最大值,如果其在 [ l u , r u ] [l_u,r_u] 的范围之外,就找到并删除它。

最后的复杂度是 O ( N l o g N ) O(NlogN)
(代码在考场上写的,较丑)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#define SF scanf
#define PF printf
#define MAXN 200010
using namespace std;
vector<int> a[MAXN],b[MAXN],ida[MAXN],idb[MAXN];
void add_edge(int u,int v,int flag,int num){
	if(flag==0){
		a[u].push_back(v);	
		a[v].push_back(u);
		ida[u].push_back(num);
		ida[v].push_back(num);
	}
	else{
		b[u].push_back(v);
		b[v].push_back(u);
		idb[u].push_back(num);
		idb[v].push_back(num);
	}
}
int la[MAXN],ra[MAXN],lb[MAXN],rb[MAXN],dfna[MAXN],dfnb[MAXN],rnkb[MAXN],rnka[MAXN];
int cnt;
void dfsa(int x,int fa=0){	
	dfna[x]=la[x]=++cnt;
	rnka[cnt]=x;
	for(int i=0;i<int(a[x].size());i++){
		int u=a[x][i];
		if(u==fa)
			continue;
		dfsa(u,x);	
	}
	ra[x]=cnt;
}
void dfsb(int x,int fa=0){
	dfnb[x]=lb[x]=++cnt;
	rnkb[cnt]=x;
	for(int i=0;i<int(b[x].size());i++){
		int u=b[x][i];
		if(u==fa)
			continue;
		dfsb(u,x);	
	}
	rb[x]=cnt;
}
int rta,rtb,ncnt;
struct node{
	int maxl,maxr,posl,posr,pl,pr;
	set<pair<int,int> >st;	
}tree[MAXN*8];
pair<int,int> Ea[MAXN],Eb[MAXN];
void get_lr(int l,int id){
	if(tree[id].st.size()){
		tree[id].maxl=tree[id].st.begin()->first;
		tree[id].posl=tree[id].st.begin()->second;
		tree[id].maxr=tree[id].st.rbegin()->first;
		tree[id].posr=tree[id].st.rbegin()->second;
	}
	else{
		tree[id].maxl=tree[id].maxr=tree[id].posl=tree[id].posr=0;	
	}
}
void update(int id){
	int pl=tree[id].pl;
	int pr=tree[id].pr;
	tree[id].maxl=tree[id].maxr=tree[id].posl=tree[id].posr=0;
	if(tree[pr].maxl==0||(tree[pl].maxl<tree[pr].maxl&&tree[pl].maxl!=0)){
		tree[id].maxl=tree[pl].maxl;
		tree[id].posl=tree[pl].posl;
	}
	else{
		tree[id].maxl=tree[pr].maxl;
		tree[id].posl=tree[pr].posl;
	}
	if(tree[pr].maxr==0||(tree[pl].maxr>tree[pr].maxr&&tree[pl].maxr!=0)){
		tree[id].maxr=tree[pl].maxr;
		tree[id].posr=tree[pl].posr;
	}
	else{
		tree[id].maxr=tree[pr].maxr;
		tree[id].posr=tree[pr].posr;
	}
}
void build(int id,int l,int r,int flag){
	if(l==r){
		if(flag==0){
			int x=rnka[l];
			for(int i=0;i<int(b[x].size());i++)
				tree[id].st.insert(make_pair(dfna[b[x][i]],idb[x][i]));
		}
		else{
			int x=rnkb[l];
			for(int i=0;i<int(a[x].size());i++)
				tree[id].st.insert(make_pair(dfnb[a[x][i]],ida[x][i]));
		}
		get_lr(l,id);
		return ;
	}
	int mid=(l+r)>>1;
	tree[id].pl=++ncnt;
	tree[id].pr=++ncnt;
	build(tree[id].pl,l,mid,flag);
	build(tree[id].pr,mid+1,r,flag);
	update(id);
}
vector<int> print;
int query(int l,int r,int id,int l1,int r1){
	if(l==r){
		if(tree[id].st.size()==0)
			return 0;
		if(tree[id].st.begin()->first<l1)
			return tree[id].st.begin()->second;
		if(tree[id].st.rbegin()->first>r1)
			return tree[id].st.rbegin()->second;
		return 0;
	}
	int mid=(l+r)>>1,res=0;
	if(l>=l1&&r<=r1){
		if(tree[id].maxl!=0&&tree[id].maxl<l1){
			if(tree[tree[id].pl].maxl<l1&&tree[tree[id].pl].maxl!=0)
				return query(l,mid,tree[id].pl,l1,r1);
			else
				return query(mid+1,r,tree[id].pr,l1,r1);
		}
		if(tree[id].maxr!=0&&tree[id].maxr>r1){
			if(tree[tree[id].pl].maxr>r1&&tree[tree[id].pl].maxr!=0)
				return query(l,mid,tree[id].pl,l1,r1);
			else
				return query(mid+1,r,tree[id].pr,l1,r1);
		}
		return 0;
	}
	if(l1<=mid)
		res=query(l,mid,tree[id].pl,l1,r1);
	if(res)
		return res;
	if(r1>mid)
		res=query(mid+1,r,tree[id].pr,l1,r1);
	return res;
}
void change(int l,int r,int id,int pos,int delx,int dely){
	if(l==r){
		tree[id].st.erase(make_pair(delx,dely));
		get_lr(l,id);
		return ;
	}
	int mid=(l+r)>>1;
	if(pos<=mid)
		change(l,mid,tree[id].pl,pos,delx,dely);
	else
		change(mid+1,r,tree[id].pr,pos,delx,dely);
	update(id);
}
queue<int> q[2];
int main(){
	int n,u,v,k;
	SF("%d",&n);
	for(int i=2;i<=n;i++){
		SF("%d",&u);
		v=i;
		add_edge(u,v,0,i-1);
		Ea[i-1]=make_pair(u,v);
	}
	for(int i=2;i<=n;i++){
		SF("%d",&u);
		v=i;
		add_edge(u,v,1,i-1);
		Eb[i-1]=make_pair(u,v);	
	}
	dfsa(1);
	cnt=0;
	dfsb(1);
	rta=++ncnt;
	build(rta,1,n,0);
	rtb=++ncnt;
	build(rtb,1,n,1);
	SF("%d",&k);
	change(1,n,rtb,dfnb[Ea[k].first],dfnb[Ea[k].second],k);
	change(1,n,rtb,dfnb[Ea[k].second],dfnb[Ea[k].first],k);
	q[0].push(k);
	int now=0;
	while(!q[now].empty()){
		while(!q[now].empty()){
			int id=q[now].front();
			print.push_back(id);
			q[now].pop();
			if(now==0){
				int x=dfna[Ea[id].first]>dfna[Ea[id].first]?Ea[id].first:Ea[id].second;
				int idx=query(1,n,rta,la[x],ra[x]);
				while(idx){
					change(1,n,rta,dfna[Eb[idx].first],dfna[Eb[idx].second],idx);
					change(1,n,rta,dfna[Eb[idx].second],dfna[Eb[idx].first],idx);
					q[now^1].push(idx);
					idx=query(1,n,rta,la[x],ra[x]);
				}
			}
			else{
				int x=dfnb[Eb[id].first]>dfnb[Eb[id].first]?Eb[id].first:Eb[id].second;
				int idx=query(1,n,rtb,lb[x],rb[x]);
				while(idx){
					change(1,n,rtb,dfnb[Ea[idx].first],dfnb[Ea[idx].second],idx);
					change(1,n,rtb,dfnb[Ea[idx].second],dfnb[Ea[idx].first],idx);
					q[now^1].push(idx);
					idx=query(1,n,rtb,lb[x],rb[x]);
				}
			}
		}
		if(now==0)
			PF("Blue\n");
		else
			PF("Red\n");
		sort(print.begin(),print.end());
		for(int i=0;i<int(print.size());i++)
			PF("%d ",print[i]);
		PF("\n");
		print.clear();
		now^=1;	
	}
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/86129199
two
今日推荐