【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\n",ans.v);
			update(1,1,node,ans.id);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity是一款强大的跨平台游戏引擎,也可以用于开发其他类型的应用程序。Unity提供了一个名为Unity Graph and Chart的工具,用于创建和展示图形和图表。 Unity Graph and Chart工具使用户能够在游戏或应用程序中轻松地创建和管理各种类型的图表,例如柱状图、饼状图、折线图等。它提供了一个直观的界面,使用户能够通过简单的拖拽和放置操作来生成图表。 使用Unity Graph and Chart,用户可以根据自己的需求自定义图表的样式和外观。它提供了丰富的样式选项,例如改变图表的颜色、调整坐标轴的格式、选择不同的图例样式等。用户还可以通过编程的方式动态地更新图表数据,使其能够实时反映应用程序中的变化。 除了基本的图表功能,Unity Graph and Chart还提供了一些额外的特性和工具来增强用户体验。例如,它可以支持多种不同的数据源,如数据库和网络数据。它还提供了一些交互式的功能,如放大、缩小、拖动等,使用户能够更好地探索图表数据。 最后,Unity Graph and Chart工具还具有良好的跨平台性能。无论是在PC、移动设备还是VR/AR设备上,都可以运行流畅,并且能够适应不同的屏幕分辨率和设备特性。 总之,Unity Graph and Chart是一个功能强大且易于使用的工具,可帮助用户在Unity引擎中创建和展示各种类型的图表。无论是用于游戏开发还是其他应用程序开发,都可以通过这个工具来有效地展示和分析数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值