【CF1416D】Graph and Queries(虚点)

带删除维护最大值显然不好做,所以考虑先把最后的图建出来,再从后往前加边。

但是询问中还带修改(让 p u = 0 p_u=0 pu=0),这样会影响后面的询问,所以也不能加边时就得到答案。

这里给出一种简单易懂的做法:

在从后往前枚举操作的时候:

  1. 如果是加边 ( u , v ) (u,v) (u,v) u u u v v v 不连通(设它们所在连通块的根分别为 a a a b b b),我们就新建一个虚点连向 a a a b b b,并且把这个虚点作为 a a a b b b 的父亲。

  2. 如果是询问 x x x,也就是询问当前 x x x 所在连通块内的最大值,我们就记录一下当前 x x x 所在连通块的根。

建好新图后,我们再从前往后扫每一个询问。对于一个询问,我们直接查询我们对这个询问记录的根的子树内的最大值,然后把它置零。这些操作具体可以用 dfn 序线段树维护。

其实这个做法的巧妙之处就在于设置了一个虚点,这个虚点起到了一个类似可持久化记录和区分版本的作用。

代码如下:

#include<bits/stdc++.h>
#include<iostream>

#define N 200010
#define M 300010
#define K 500010

using namespace std;

struct Edge
{
	int u,v;
}e[M];

struct Query
{
	int opt,x;
}q[K];

struct data
{
	int v,id;
	data(){v=-1*1*1*1;}
	data(int a,int b){v=a,id=b;}
}maxn[(N+K)<<2];

bool operator < (data a,data b)
{
	return a.v<b.v;
}

int n,m,Q,v[N+K],fa[N+K];
int cnt,head[N+K],to[N+K],nxt[N+K];
int node,idx,dfn[N+K],rk[N+K],size[N+K];
bool del[M],vis[N+K];

int find(int x)
{
	return x==fa[x]?x:(fa[x]=find(fa[x]));
}

void adde(int u,int v)
{
	to[++cnt]=v;
	nxt[cnt]=head[u];
	head[u]=cnt;
}

void dfs(int u)
{
	dfn[u]=++idx;
	rk[idx]=u;
	size[u]=1;
	for(int i=head[u];i;i=nxt[i])
	{
		int v=to[i];
		dfs(v);
		size[u]+=size[v];
	}
}

void up(int k)
{
	maxn[k]=max(maxn[k<<1],maxn[k<<1|1]);
}

void build(int k,int l,int r)
{
	if(l==r)
	{
		maxn[k]=data(v[rk[l]],l);
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	up(k);
}

data query(int k,int l,int r,int ql,int qr)
{
	if(ql<=l&&r<=qr) return maxn[k];
	int mid=(l+r)>>1;
	data ans;
	if(ql<=mid) ans=max(ans,query(k<<1,l,mid,ql,qr));
	if(qr>mid) ans=max(ans,query(k<<1|1,mid+1,r,ql,qr));
	return ans;
}

void update(int k,int l,int r,int x)
{
	if(l==r)
	{
		maxn[k].v=0;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid) update(k<<1,l,mid,x);
	else update(k<<1|1,mid+1,r,x);
	up(k);
}

int main()
{
	scanf("%d%d%d",&n,&m,&Q);
	node=n;
	for(int i=1;i<=n;i++) 
		scanf("%d",&v[i]);
	for(int i=1;i<=m;i++)
		scanf("%d%d",&e[i].u,&e[i].v);
	for(int i=1;i<=Q;i++)
	{
		scanf("%d%d",&q[i].opt,&q[i].x);
		if(q[i].opt==2) del[q[i].x]=1;
	}
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=m;i++)
	{
		if(!del[i])
		{
			int a=find(e[i].u),b=find(e[i].v);
			if(a!=b)
			{
				fa[b]=a;
				adde(a,b);
			}
		}
	}
	for(int i=Q;i>=1;i--)
	{
		if(q[i].opt==1) q[i].x=find(q[i].x);
		else
		{
			int a=find(e[q[i].x].u),b=find(e[q[i].x].v);
			if(a!=b)
			{
				++node;//新建虚点
				fa[a]=fa[b]=fa[node]=node;
				adde(node,a),adde(node,b);
			}
		}
	}
	for(int i=1;i<=node;i++)
	{
		int a=find(i);
		if(!vis[a])
		{
			vis[a]=true;
			dfs(a);
		}
	}
	build(1,1,node);
	for(int i=1;i<=Q;i++)
	{
		if(q[i].opt==1)
		{
			data ans=query(1,1,node,dfn[q[i].x],dfn[q[i].x]+size[q[i].x]-1);
			printf("%d
",ans.v);
			update(1,1,node,ans.id);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/ez-lcw/p/14448628.html