【CF1416D】Graph and Queries

题目

题目链接:https://codeforces.com/problemset/problem/1416/D
给定一个 \(n\) 个点 \(m\) 条边的无向图,第 \(i\) 个点的点权初始值为 \(p_i\),所有 \(p_i\) 互不相同。
接下来进行 \(q\) 次操作,分为两类:

  • \(\tt 1\ v\) 查询与 \(v\) 连通的点中, \(p_u\) 最大的点 \(u\) 并输出 \(p_u\),然后让 \(p_u=0\)
  • \(\tt 2\ i\) 将第 \(i\) 条边删掉。

\(n\leq 2\times 10^5,m\leq 3\times 10^5,Q\leq 5\times 10^5\)

思路

我会线段树分治 + 左偏树!
看到删边自然想到时间倒流变为加边,但是时间倒流后操作 \(1\) 的顺序就错了。
把一条边的权值设为这条边删除之前,有多少次询问操作。求出这张图的 Kruskal 重构树,这样处理之后,对于任意一个点 \(x\),它第 \(k\) 次询问时可以到达的点一定是重构树上 \(x\) 某一个祖先的子树。
可以通过倍增找到这一个点,然后问题转化为单点修改,子树求最大值,线段树维护即可。
时间复杂度 \(O(Q\log n)\)

代码

#include <bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second
using namespace std;

const int N=800010,LG=20;
int n,m,Q,Q1,tot,head[N],a[N],b[N],father[N],id[N],siz[N],f[N][LG+1];

struct node
{
	int u,v,t;
}rd[N];

bool cmp(node x,node y)
{
	return x.t<y.t;
}

struct edge
{
	int next,to;
}e[N];

void add(int from,int to)
{
	e[++tot]=(edge){head[from],to};
	head[from]=tot;
}

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

void dfs(int x,int fa)
{
	f[x][0]=fa; id[x]=++tot; siz[x]=1;
	for (int i=1;i<=LG;i++)
		f[x][i]=f[f[x][i-1]][i-1];
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (v!=fa) dfs(v,x),siz[x]+=siz[v];
	}
}

struct SegTree
{
	pair<int,int> maxn[N*4];
	
	void update(int x,int l,int r,int k,int v)
	{
		if (l==r) { maxn[x]=mp(v,l); return; }
		int mid=(l+r)>>1;
		if (k<=mid) update(x*2,l,mid,k,v);
			else update(x*2+1,mid+1,r,k,v);
		maxn[x]=max(maxn[x*2],maxn[x*2+1]);
	}
	
	pair<int,int> query(int x,int l,int r,int ql,int qr)
	{
		if (ql<=l && qr>=r) return maxn[x];
		int mid=(l+r)>>1; pair<int,int> res=mp(0,0);
		if (ql<=mid) res=max(res,query(x*2,l,mid,ql,qr));
		if (qr>mid) res=max(res,query(x*2+1,mid+1,r,ql,qr));
		return res;
	}
}seg;

int main()
{
//	freopen("data.txt","r",stdin);
	memset(head,-1,sizeof(head));
	scanf("%d%d%d",&n,&m,&Q1);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for (int i=1;i<=m;i++)
		scanf("%d%d",&rd[i].u,&rd[i].v);
	tot=n;
	for (int i=1,opt,x;i<=Q1;i++)
	{
		scanf("%d%d",&opt,&x);
		if (opt==1) b[++Q]=x;
		if (opt==2) rd[x].t=++tot,a[tot]=Q;
	}
	for (int i=1;i<=m;i++)
		if (!rd[i].t) rd[i].t=++tot,a[tot]=Q;
	for (int i=1;i<=tot;i++) father[i]=i;
	sort(rd+1,rd+1+m,cmp);
	tot=0;
	for (int i=m;i>=1;i--)
	{
		int x=find(rd[i].u),y=find(rd[i].v);
		if (x!=y)
		{
			add(rd[i].t,x); add(rd[i].t,y);
			father[x]=father[y]=rd[i].t;
		}
	}
	tot=0;
	for (int i=1;i<=n;i++)
		if (!id[find(i)]) dfs(find(i),0);
	for (int i=1;i<=n;i++)
		seg.update(1,1,tot,id[i],a[i]);
	for (int i=1;i<=Q;i++)
	{
		int x=b[i];
		for (int j=LG;j>=0;j--)
			if (a[f[x][j]]>=i) x=f[x][j];
		pair<int,int> ans=seg.query(1,1,tot,id[x],id[x]+siz[x]-1);
		cout<<ans.fi<<"\n";
		if (ans.fi) seg.update(1,1,tot,ans.se,0);
	}
	return 0;
}
posted @ 2021-08-22 10:14  stoorz  阅读(44)  评论(0编辑  收藏  举报