正题
luogu 4219
题目大意
给你一棵树(初始都无连边),让你进行以下操作:
1.连接两个点
2.查询一条边被多少条路径经过
解题思路
因为有边的修改,可以用LCT来维护这棵树
一条边的经过次数,就相当于连接的两棵子树的大小之积
那么维护子树大小即可
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 100010
using namespace std;
int n, q, x, y;
char c;
struct LCT
{#define ls son[x][0]#define rs son[x][1]int p[N], siz[N], size[N], fa[N], son[N][2];bool NR(int x){return fa[x] && (son[fa[x]][0] == x || son[fa[x]][1] == x);}bool IRS(int x){return son[fa[x]][1] == x;}void push_up(int x){size[x] = size[ls] + size[rs] + siz[x];return;}void pushr(int x){p[x] ^= 1;swap(ls, rs);return;}void push_down(int x){if (p[x]){p[x] = 0;if (ls) pushr(ls);if (rs) pushr(rs);}return;}void rotate(int x){int y = fa[x], z = fa[y], k = IRS(x), g = son[x][!k];if (NR(y)) son[z][IRS(y)] = x;if (g) fa[g] = y;fa[y] = x;fa[x] = z;son[x][!k] = y;son[y][k] = g;push_up(y);return;}void push_hall(int x){if (NR(x)) push_hall(fa[x]);push_down(x);return;}void Splay(int x){push_hall(x);while(NR(x)){if (NR(fa[x])){if (IRS(x) == IRS(fa[x])) rotate(fa[x]);else rotate(x);}rotate(x);}push_up(x);return;}void access(int x){for (int y = 0; x; x = fa[y = x]){Splay(x);siz[x] += size[rs] - size[y];rs = y;push_up(x);}return;}void make_root(int x){access(x);Splay(x);pushr(x);return;}void Split(int x, int y){make_root(x);access(y);Splay(y);return;}void link(int x, int y){make_root(x);make_root(y);fa[x] = y;siz[y] += size[x];push_up(y);return;}
}T;
int main()
{scanf("%d%d", &n, &q);for (int i = 1; i <= n; ++i)T.size[i] = T.siz[i] = 1;while(q--){scanf("%s%d%d", &c, &x, &y);if (c == 'A') T.link(x, y);else{T.Split(x, y);printf("%lld\n", 1ll * T.siz[x] * T.siz[y]);}}return 0;
}