「APIO2019」桥梁(询问分块+并查集)

询问每$S$个分块后,每次对于所有块内未被更改的边 及 所有询问 排序,然后依次加入并查集,这一部分复杂度为$O(m \frac{q} {S}(\log m+\alpha(n)))$

对于$S$条被改变的边,对于每个询问分别考虑这些边的贡献,复杂度为$O(qS)$,由于涉及到并查集回撤的问题,可以使用按秩合并,复杂度为$O(qS\log S)$

按照上面两步暴力实现,复杂度大概可以做到$O((m+q)\sqrt{q}\log n)$

实际可行的优化有:

用平衡树实现排序,每次暴力遍历,第一部分复杂度降为$O(q\log m+m\frac{q} {S} \alpha(n))$

由于最多访问到$O(S)$个联通块,第二部分用$dfs$遍历来实现,复杂度降为$O(q S \alpha(n))$(遍历过程中要访问联通块编号)

复杂度可以降到约$O((m+q)\sqrt {q} \cdot \alpha(n))$

以下是暴力实现的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
#define pb push_back
char IO;
int rd(){
int s=0;
while(!isdigit(IO=getchar()));
do s=(s<<1)+(s<<3)+(IO^'0');
while(isdigit(IO=getchar()));
return s;
}

const int N=1e5+10;
int n,m,S,q,qc;
struct Edge{
int u,v,w;
bool operator < (Edge __) const { return w<__.w; }
} A[N],B[N],Q[N];
struct Node{ int t,w; };
vector <Node> G[N];
int uid[N],uc,fa[N],sz[N],ux[N],uy[N],rc,ans[N];
int Find(int x){ while(fa[x]!=x) x=fa[fa[x]]; return x; }
void Union(int x,int y){
x=Find(x),y=Find(y);
if(x==y) return;
if(sz[x]>sz[y]) swap(x,y);
ux[++rc]=x,uy[rc]=y;
fa[x]=y,sz[y]+=sz[x]; // 按秩合并用于回撤
}

int main(){
n=rd(),m=rd();
rep(i,1,m) A[i].u=rd(),A[i].v=rd(),A[i].w=rd();
S=sqrt(3*(n+m));
rep(i,1,q=rd()) {
ans[i]=-1;
int opt=rd(),x=rd(),y=rd();
if(opt==1) G[x].pb((Node){i,y});
else Q[++qc]=(Edge){i,x,y};
if(qc%S==0 || i==q) {
if(!qc) continue;
int c=0;
rep(i,1,m) if(!G[i].size()) B[++c]=A[i];
else uid[++uc]=i;
sort(B+1,B+c+1),sort(Q+1,Q+qc+1);
rep(i,1,n) fa[i]=i,sz[i]=1;
int p=c;
drep(i,qc,1) {
while(p && B[p].w>=Q[i].w) Union(B[p].u,B[p].v),p--;
rc=0;
rep(j,1,uc) {
int x=uid[j],w=A[x].w;
for(auto k:G[x]) if(k.t<=Q[i].u) w=k.w;
else break; // 找到询问时这条边的权值
if(w>=Q[i].w) Union(A[x].u,A[x].v);
}
ans[Q[i].u]=sz[Find(Q[i].v)];
drep(j,rc,1) fa[ux[j]]=ux[j],fa[uy[j]]=uy[j],sz[uy[j]]-=sz[ux[j]];// 回撤
rc=0;
}
rep(i,1,uc) A[uid[i]].w=G[uid[i]].rbegin()->w,G[uid[i]].clear();
uc=qc=0;
}
}
rep(i,1,q) if(~ans[i]) printf("%d\n",ans[i]);
}