[APIO2019]桥梁 题解
题意简述
给定一个 \(n\) 个点,\(m\) 条边的无向联通图,边有边权,要求支持以下 \(q\) 次操作:
-
修改某条边的边权
-
给定 \(x,v\),求从 \(x\) 点出发,只能走边权 \(≥v\) 的边,问最多能到达几个点
\(n≤5\times 10^4, m,q≤10^5\)
Solution
如果没有修改,这个问题是简单的,直接给边和询问以权值排序,并查集搞一下就好了。
那如果修改比较少呢?也很好做,记有修改的边的集合为 \(S\)。
还是像离线做法一样,给边排序一下,然后分类讨论一下:
-
对于不在 \(S\) 里的边,还是像离线的时候直接合并就好了。
-
对于在 \(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;
}

浙公网安备 33010602011771号