[UOJ207]共价大爷游长沙(随机,动态树维护子树和)

Description

维护一个数据结构,要求对树支持以下操作:

  1. 添加一条边,删除一条边。
  2. 在集合 S S 中加入点对 (x,y) ( x , y )
  3. 删除集合中的某个点对。
  4. 询问某条边是否被 S S 中所有点对间的路径经过。

Solution

myy的题,感觉好神啊,只会做50分。

考虑询问的边 (x,y) ( x , y ) 被所有点对路径经过相当于以 x x 为根时,所有点对都恰有一个端点在以 y y 的子树中。

所以对每个点对随机一个权值,并让端点异或上这个权值。每次询问时查询以 y y 为根的子树异或和是否等于总异或和即可。

#include 
using namespace std;

const int maxn = 100005, maxm = 300005;
int n, m, Id, S, x[maxm], y[maxm], z[maxm], cnt;
int ch[maxn][2], vsum[maxn], sum[maxn], f[maxn], val[maxn], rev[maxn];

int Rand(int l,int r)
{
    double dou=1.0*rand()/RAND_MAX;
    return dou*(r-l+1)+l;
}

#define isroot(x) (ch[f[x]][0] != x && ch[f[x]][1] != x)
#define get(x) (ch[f[x]][1] == x)
#define update(x) sum[x] = vsum[x] ^ val[x] ^ sum[ch[x][0]] ^ sum[ch[x][1]]
inline void rotate(int x)
{
    int fa = f[x], gfa = f[fa], k = get(x);
    if(!isroot(fa)) ch[gfa][get(fa)] = x;
    ch[fa][k] = ch[x][k ^ 1]; f[ch[x][k ^ 1]] = fa;
    ch[x][k ^ 1] = fa; f[fa] = x;
    f[x] = gfa;
    update(fa); update(x);
}

int stk[maxn], top;
inline void pushdown(int x)
{
    if(!x || !rev[x]) return ;
    if(ch[x][0]) rev[ch[x][0]] ^= 1;
    if(ch[x][1]) rev[ch[x][1]] ^= 1;
    swap(ch[x][0], ch[x][1]); rev[x] = 0;
}

inline void splay(int x)
{
    stk[top = 1] = x;
    while(!isroot(x)) stk[++top] = x = f[x];
    while(top) pushdown(stk[top--]);
    x = stk[1];
    while(!isroot(x)) {
        int fa = f[x];
        if(!isroot(fa)) get(fa) ^ get(x) ? rotate(x) : rotate(fa);
        rotate(x);
    }
    update(x);
}

inline void access(int x)
{
    for(int y = 0; x; y = x, x = f[x]) {
        splay(x); vsum[x] ^= sum[ch[x][1]] ^ sum[y]; ch[x][1] = y; 
        update(x);
    }
}

inline void make_root(int x) {access(x); splay(x); rev[x] ^= 1;}
inline void link(int x, int y) {make_root(x); make_root(y); vsum[y] ^= sum[x]; f[x] = y;}
inline void cut(int x, int y) {make_root(x); access(y); splay(y); f[x] = ch[y][0] = 0; update(x); update(y);}

inline void insert(int u, int v, int w)
{
    make_root(u); splay(u); val[u] ^= w; sum[u] ^= w;
    make_root(v); splay(v); val[v] ^= w; sum[v] ^= w;
}

inline bool query(int x, int y)
{
    make_root(x); access(y); splay(y);
    return sum[x] == S;
}

int main()
{
    freopen("visit.in", "r", stdin);
    freopen("visit.out", "w", stdout);

    scanf("%d%d%d", &Id, &n, &m);
    for(int u, v, i = 1; i < n; ++i) 
        scanf("%d%d", &u, &v), link(u, v);

    for(int opt, u, v, w, i = 1; i <= m; ++i) {
        scanf("%d", &opt);
        if (opt == 1) {
            scanf("%d%d", &u, &v); cut(u, v);
            scanf("%d%d", &u, &v); link(u, v);
        }else if (opt == 2) {
            scanf("%d%d", &u, &v); w = Rand(1, 1000000000); S ^= w;
            insert(u, v, w);
            ++cnt; x[cnt] = u; y[cnt] = v; z[cnt] = w;
        }else if (opt == 3) {
            scanf("%d", &u); insert(x[u], y[u], z[u]); S ^= z[u];
        }else if (opt == 4) {
            scanf("%d%d", &u, &v);
            if(query(u, v)) puts("YES");
            else puts("NO");
        }
    }
    return 0;
}

你可能感兴趣的:(数据结构——动态树/LCT,算法——随机)