zoukankan      html  css  js  c++  java
  • BJOI2014 大融合

    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) << '
    ';
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    运行Jmeter时,出现java.util.prefs.WindowsPreferences <init>
    Jmeter下载安装及JDK安装
    面试常用-基础理论(五)
    Fiddler (六) 最常用的快捷键
    Fiddler (五) Mac下使用Fiddler
    Fiddler (四) 实现手机的抓包
    Fiddler (三) Composer创建和发送HTTP Request
    Fiddler (二) Script 用法
    Web调试工具——Fiddler介绍
    生成任意位数随机字符串
  • 原文地址:https://www.cnblogs.com/tztqwq/p/14297689.html
Copyright © 2011-2022 走看看