ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

BJOI2014 大融合

2021-01-19 15:02:18  阅读:186  来源: 互联网

标签:int siz void BJOI2014 son fa 融合 hd


  1. 保证初始所有点都孤立
  2. 保证连的边的端点在连这条边前不联通

即整个图一直都是森林。

先连好所有的边,定好每棵树的根。

这样,每次询问就是在树上的一条边 (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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有