[APIO2019]桥梁 题解

题意简述

给定一个 \(n\) 个点,\(m\) 条边的无向联通图,边有边权,要求支持以下 \(q\) 次操作:

  • 修改某条边的边权

  • 给定 \(x,v\),求从 \(x\) 点出发,只能走边权 \(≥v\) 的边,问最多能到达几个点

\(n≤5\times 10^4, m,q≤10^5\)

Solution

如果没有修改,这个问题是简单的,直接给边和询问以权值排序,并查集搞一下就好了。

那如果修改比较少呢?也很好做,记有修改的边的集合为 \(S\)

还是像离线做法一样,给边排序一下,然后分类讨论一下:

  1. 对于不在 \(S\) 里的边,还是像离线的时候直接合并就好了。

  2. 对于在 \(S\) 里的边,因为 \(|S|\) 是小的,所以我们可以暴力遍历 \(S\) 集合,看看在这个时间上边是什么权值,然后再判断是否合并,最后撤销。

到这里问题就很 \(naive\) 了,直接对时间轴分块,在每个块内跑刚刚那个做法,就做完了。

总复杂度 \(O(q\sqrt q\) \(log\) \(n)\)

Code

#include<bits/stdc++.h>
#define IL inline
#define RE register
#define N 50050
#define M 100100
#ifdef ONLINE_JUDGE
    char __B[1<<15],*__S=__B,*__T=__B;
    #define getchar() (__S==__T&&(__T=(__S=__B)+fread(__B,1,1<<15,stdin),__S==__T)?EOF:*__S++)
#endif
IL int read()
{
	int x=0;char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9')x=x*10+(ch^48),ch=getchar();
	return x;
}

const int B=1374;

int n,m,t;
struct Edge
{
	int u,v,w,id;
	bool operator <(const Edge &x)const
	{
		return w>x.w;
	}
}e[M],real[M];

struct Operation{int b,r,id;}o[M];

struct Ques
{
	int s,w,id;
	bool operator <(const Ques &x)const
	{
		return w>x.w;
	}
}q[M];

int cnt_o,cnt_q;
int ans[M];
bool vis[M];
int fa[N],size[N];

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

struct Stack{int x,y;}s[M];

int top;

IL void merge(int x,int y)
{
	x=find(x),y=find(y);
	if(x==y)return;
	if(size[x]<size[y])std::swap(x,y);
	size[x]+=size[y];
	fa[y]=x;
	s[++top]=(Stack){x,y};
}

IL void del()
{
	size[s[top].x]-=size[s[top].y];
	fa[s[top].y]=s[top].y;
	--top;
}

IL void solve()
{
	memset(vis,0,sizeof(vis));
	for(RE int i=1;i<=n;++i)size[i]=1,fa[i]=i;
	for(RE int i=1;i<=cnt_o;++i)vis[o[i].b]=true;
	std::sort(e+1,e+1+m),std::sort(q+1,q+1+cnt_q);
	int p=1;
	for(RE int i=1;i<=cnt_q;++i)
	{
		while(p<=m&&e[p].w>=q[i].w)!vis[e[p].id]?merge(e[p].u,e[p].v),++p:++p; 
		int last=top;
		for(RE int j=cnt_o;j;--j)if(vis[o[j].b]&&o[j].id<q[i].id)
		{
			o[j].r>=q[i].w?merge(real[o[j].b].u,real[o[j].b].v):void();
			vis[o[j].b]=false;
		}
		for(RE int j=cnt_o;j;--j)if(vis[o[j].b])real[o[j].b].w>=q[i].w?merge(real[o[j].b].u,real[o[j].b].v):void();		
		ans[q[i].id]=size[find(q[i].s)];
		for(RE int j=1;j<=cnt_o;++j)vis[o[j].b]=true;
		while(top^last)del();
	}
	for(RE int i=cnt_o;i;--i)if(vis[o[i].b])
	{
		real[o[i].b].w=o[i].r;
		vis[o[i].b]=false;
	}
	for(RE int i=1;i<=m;++i)e[i]=real[i];
	cnt_o=cnt_q=top=0;
}

int main()
{
	n=read(),m=read();
	for(RE int i=1;i<=m;++i)e[i]=real[i]=(Edge){read(),read(),read(),i};
	t=read();
	int opt,a,b;
	for(RE int i=1;i<=t;++i)
	{
		opt=read(),a=read(),b=read();
		if(opt^2)o[++cnt_o]=(Operation){a,b,i};
		else q[++cnt_q]=(Ques){a,b,i};
		if(i%B==0)solve();
	}
	if(t%B)solve();
	for(RE int i=1;i<=t;++i)ans[i]&&printf("%d\n",ans[i]);
	return 0;
}
posted @ 2021-07-21 21:21  Nesraychan  阅读(141)  评论(0)    收藏  举报