F. Graph and Queries(反向并查集&dfs序&线段树)

思路:反向并查集 + d f s +dfs +dfs + + +线段树

对询问进行离线操作,从后往前,最开始建立一张删除所有询问边后的图,然后倒着重构图,如果是操作一就更新查询结点为其祖先结点: Q [ i ] . s e = f i n d ( Q [ i ] . s e ) Q[i].se=find(Q[i].se) Q[i].se=find(Q[i].se)

如果是操作二就利用并查集建立新结点连边,具体就是新建立一个结点其儿子为这条边的两个结点,父亲也同时更新为该新结点。

然后对图跑 d f s dfs dfs序,然后转换为线段树求区间最值问题。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
#define il inline
int n,m,q,cnt;
int a[N],f[N],in[N],out[N],pos[N],del[N];
PII edge[N],Q[N]; 
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
vector<int>g[N];
struct node{
	int l,r,mx;
}tr[N<<2];
void Merge(int x,int y){
	x=find(x),y=find(y);
	if(x==y) return;
	n++;f[n]=n,f[x]=f[y]=n;
	g[n].pb(x),g[n].pb(y);
}
void dfs(int u){
	in[u]=++cnt;
	for(int v:g[u]) if(!in[v]) dfs(v);
	out[u]=cnt;
}
void re(int x){
	tr[x].mx=max(tr[lx].mx,tr[rx].mx);
}
void build(int x,int l,int r){
	tr[x].l=l,tr[x].r=r,tr[x].mx=0;
	if(l==r){
		return;
	}
	int mid=(l+r)>>1;
	build(lx,l,mid);
	build(rx,mid+1,r);
}
void upd(int x,int p,int val){
	if(tr[x].l==tr[x].r){
		tr[x].mx=val;return;
	}
	int mid=(tr[x].l+tr[x].r)>>1;
	if(p<=mid) upd(lx,p,val);
	else upd(rx,p,val);
	re(x);
}
int que(int x,int l,int r){
	if(tr[x].l>=l&&tr[x].r<=r) return tr[x].mx;
	int ans=0,mid=(tr[x].l+tr[x].r)>>1;
	if(l<=mid) ans=max(ans,que(lx,l,r));
	if(r>mid) ans=max(ans,que(rx,l,r));
	return ans;
}
int main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]),pos[a[i]]=i,f[i]=i;
	}
	for(int i=1;i<=m;i++)
		scanf("%d%d",&edge[i].fi,&edge[i].se);
	for(int i=1;i<=q;i++){
		scanf("%d%d",&Q[i].fi,&Q[i].se);
		if(Q[i].fi==2) del[Q[i].se]=1;
	}
	for(int i=1;i<=m;i++)
		if(!del[i]) Merge(edge[i].fi,edge[i].se);
	for(int i=q;i;i--){
		if(Q[i].fi==1) Q[i].se=find(Q[i].se);
		else Merge(edge[Q[i].se].fi,edge[Q[i].se].se);
	}
	for(int i=1;i<=n;i++)
		if(f[i]==i) dfs(i);
	build(1,1,n);
	for(int i=1;i<=n;i++) upd(1,in[i],a[i]);
	for(int i=1;i<=q;i++){
		if(Q[i].fi==1){
			int ans=que(1,in[Q[i].se],out[Q[i].se]);
			printf("%d\n",ans);
			if(ans) upd(1,in[pos[ans]],0);
		}
	}
	return 0;
}

F. Graph and Queries(反向并查集&dfs序&线段树)_#define