BJOI2014 大融合
作者:互联网
- 保证初始所有点都孤立
- 保证连的边的端点在连这条边前不联通
即整个图一直都是森林。
先连好所有的边,定好每棵树的根。
这样,每次询问就是在树上的一条边 (fa[x], x), 答案是边两边连通块 size 的乘积。
fa[x] 那边的大小不好办, x 这边的正好是一个子树型的询问, 连通块总的 size 可以简单搞, 故问题焦点是 x 这边的大小。
考虑连一条边 (v = fa[u], u) 对子树和的影响, 那就是 while(v) siz[v] += siz[u], v = fa[v]
这样的感觉。
考虑用并查集维护一个点能跳 fa 跳到的最上面的点, 对于链加+单点求值直接差分+树状数组即可 O(nlog2n), 建议不要像我一样有事没事写个树剖(。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 233;
int n, Q;
struct cmd{ int op,x,y; } comm[N];
int ecnt, hd[N], nt[N*2+1], vr[N*2+1];
void ad(int x, int y) { nt[++ecnt] = hd[x], hd[x] = ecnt, vr[ecnt] = y; }
int dep[N], siz[N], fa[N], son[N], tp[N];
int dfntot, in[N], out[N];
void dfs1(int x, int F, int D) {
dep[x] = D, siz[x] = 1, fa[x] = F;
for(int i=hd[x]; i; i=nt[i]) {
int y = vr[i];
if(y == F) continue;
dfs1(y, x, D + 1);
siz[x] += siz[y];
if(siz[y] > siz[son[x]]) son[x] = y;
}
}
void dfs2(int x, int T) {
in[x] = ++dfntot;
tp[x] = T;
if(son[x]) dfs2(son[x], T);
for(int i=hd[x]; i; i=nt[i]) {
int y = vr[i];
if(y == fa[x] || y == son[x]) continue;
dfs2(y, y);
}
out[x] = dfntot;
}
struct dsu{
int fa[N], siz[N];
void init(int n) {
for(int i=1; i<=n; ++i) siz[fa[i]=i] = 1;
}
int fid(int x) { return fa[x]==x ? x : fa[x]=fid(fa[x]);}
void lef(int x, int y) { y = fid(y); siz[fa[x]=y] += siz[x]; }
int sz(int x) {return siz[fid(x)];}
} S;
int t[N];
void ins(int x, int v) {
for(;x<=n;x+=(x&(-x))) t[x]+=v;
}
int ask_(int x) {int res=0;
for(;x;x-=(x&(-x))) res+=t[x];
return res;
}
int ask(int l, int r) { return ask_(r) - ask_(l-1);}
int main()
{
scanf("%d%d", &n, &Q);
char op[5];
for(int i=1; i<=Q; ++i) {
scanf("%s%d%d", op, &comm[i].x, &comm[i].y);
comm[i].op = (op[0] == 'A') ? 1 : 2;
if(comm[i].op == 1) ad(comm[i].x, comm[i].y), ad(comm[i].y, comm[i].x);
}
for(int i=1; i<=n; ++i) if(!dep[i]) dfs1(i, 0, dep[i] = 1), dfs2(i, i);
S.init(n);
// for(int i=1; i<=n; ++i) ins(i, 1);
for(int i=1; i<=Q; ++i) {
int x = comm[i].x, y = comm[i].y;
if(fa[x] != y) swap(x,y);
// fa[x] == y
if(comm[i].op == 1)
{
int Top = S.fid(y);
int sizx = ask(in[x], out[x]) + 1;
ins(in[y], sizx);
if(fa[Top]) ins(in[fa[Top]], -sizx);
S.lef(x, y);
}
else
{
int Siz = S.sz(y);
int sizx = ask(in[x], out[x]) + 1;
cout << 1ll * sizx * (Siz - sizx) << '\n';
}
}
return 0;
}
标签:int,siz,void,BJOI2014,son,fa,融合,hd 来源: https://www.cnblogs.com/tztqwq/p/14297689.html