版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013578420/article/details/82381956
题目链接
https://nanti.jisuanke.com/t/30995
题目大意
给你一棵节点数为n的树, 有m个操作
1 x y: 如果x,y不在一个连通块内则将x, y连一条边, 否则输出一行’-1’
2 x y: 如果x,y在一个连通块内, 将x设为根, 删除y与它父亲的连边, 否则输出一行’-1’
3 x: 询问x所处连通块内, 将x设为根, 假设x上有一个点, 等概率的向相邻节点扩散, 直到又回到了x, 求期望经过的边数 mod 998244353。 如果x是孤立点则输出一行’0’。
题目思路
本质就是一个LCT题。
对于询问3, 答案是2*size[x]/deg[x], size[x]为子树大小, deg[x]为x的度数。
故在LCT过程中, 顺带维护每个节点的真实子树大小和度数即可。
Code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <bitset>
#include <map>
#include <stack>
#include <set>
#define ls ch[x][0]
#define rs ch[x][1]
#define ll long long
#define pi pair<int, int>
#define mp make_pair
#define fi first
#define se second
using namespace std;
int gi(){
int ret = 0; char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)){
ret = ret * 10 + c - '0';
c = getchar();
}
return ret;
}
const int N = (int)1e5 + 10;
const int mo = 998244353;
int n, m;
int fa[N], ch[N][2], sz[N], szxv[N], deg[N]; bool flag[N];
ll pw(ll x, ll k){
ll ret = 1;
for (; k; k >>= 1, x = x * x % mo)
if (k & 1) ret = ret * x % mo;
return ret;
}
bool IsRt(int x){return ch[fa[x]][0] != x && ch[fa[x]][1] != x;}
void ud(int x){
sz[x] = szxv[x] + sz[ch[x][0]] + sz[ch[x][1]] + 1;
}
void pd(int x){
if (!x) return;
if (flag[x]){
swap(ch[x][1], ch[x][0]);
if (ch[x][1]) flag[ch[x][1]] ^= 1;
if (ch[x][0]) flag[ch[x][0]] ^= 1;
flag[x] = 0;
}
}
void rotate(int x, int k){
int y = fa[x], z = fa[y];
int tmp = ch[x][k];
if (!IsRt(y)) ch[z][ch[z][1] == y] = x;
fa[x] = z;
ch[x][k] = y;
fa[y] = x;
ch[y][!k] = tmp;
if (tmp) fa[tmp] = y;
ud(y), ud(x);
}
void splay(int x){
pd(x);
while (!IsRt(x)){
int y = fa[x], z = fa[y];
pd(z), pd(y), pd(x);
int k = ch[y][0] == x;
if (IsRt(y)) {rotate(x, k); break;}
if (ch[z][!k] == y) rotate(y, k), rotate(x, k);
else rotate(x, k), rotate(x, !k);
}
}
void Access(int x){
int u = x, v = 0;
while (u){
splay(u);
szxv[u] += sz[ch[u][1]] - sz[v];
ch[u][1] = v;
ud(u);
v = u;
u = fa[u];
}
}
int GetRt(int x){
Access(x);
splay(x);
pd(x);
while (ch[x][0]) {x = ch[x][0]; pd(x);}
return x;
}
void MkRt(int x){
Access(x);
splay(x);
flag[x] ^= 1;
}
void link(int a, int b){
MkRt(a);
splay(a);
fa[a] = b;
szxv[b] += sz[a];
}
void cut(int a, int b){
MkRt(a);
Access(b);
splay(b);
deg[b] --;
int p = ch[b][0];
do{
pd(p);
if (ch[p][1]) p = ch[p][1];
else break;
}while(1);
deg[p] --;
fa[ch[b][0]] = 0;
ch[b][0] = 0;
ud(b);
}
int main()
{
n = gi(), m = gi();
for (int i = 1; i <= n; i ++) sz[i] = 1;
for (int i = 2, u, v; i <= n; i ++){
u = gi(), v = gi();
if (GetRt(u) != GetRt(v)){
link(u, v);
deg[u] ++, deg[v] ++;
}
}
int t, x, y;
while (m --){
t = gi();
if (t == 1){
x = gi(), y = gi();
if (GetRt(x) != GetRt(y)){
link(x, y);
deg[x] ++, deg[y] ++;
}
else puts("-1");
}
if (t == 2){
x = gi(), y = gi();
if (GetRt(x) == GetRt(y) && x != y){
cut(x, y);
}
else puts("-1");
}
if (t == 3){
x = gi();
MkRt(x);
ll ret = 2ll * (sz[x] - 1) * pw(deg[x], mo - 2) % mo;
printf("%lld\n", ret);
}
}
return 0;
}