[计蒜客 2018南京网络赛F] An Easy Problem On The Trees

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013578420/article/details/82381956

题目链接

https://nanti.jisuanke.com/t/30995

题目大意

给你一棵节点数为n的树, 有m个操作 ( 1 n , m 10 5 )
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;
}


猜你喜欢

转载自blog.csdn.net/u013578420/article/details/82381956