J- Graph【2019ICPC沈阳】【LCT+哈希】

题目链接


  有两棵上限是N个点的树(有时候是森林),有两个小伙伴分别操作自己的一棵树,小伙伴A和小伙伴B,现在小伙伴们想知道对方的树上能相互抵达的两个结点,在本棵树上是否也是可行的,也就是树的同构“同分异构”(每棵子树含有的结点相同,但是结构可能不同)。如果满足,则为YES,否则是NO。

  有一种很神奇的方法,叫做给一条边的两个端点,同时异或一个值,那么如果说这两个端点在另一棵树上也是相连的,那么表明了他们的异或和应该是为0的,那么如果不在同一个树中的话,两棵树上的点的总的异或和应该都是有剩余的,所以我们可以rand()随机数来产生这个异或值,然后利用一个动态树形数据结构来维护,就是LCT了。

  LCT可以很好的维护一条链上的信息,如果要维护一棵树呢?我们知道有实虚边这一说法。实边中的左儿子是它的父亲结点,实边中的右儿子是它的子结点,但是还有一些实虚边,虚边的值我们依然也要去维护下来,什么时候会产生虚边?只有在access()函数中会产生虚边的变化,因为它要将这个点到根结点的这条链给拉出来,所以会使得虚边实边的变化。

  我们如果用other来记录虚边上的值的话,会有这样的情况:

void access(int x)
{
    int y = 0;
    while(x)
    {
        Splay(x);
        other[x] ^= s[c[x][1]];
        other[x] ^= s[y];
        c[x][1] = y;
        pushup(x);
        y = x; x = fa[x];
    }
}

  我们要更换实虚边了,于是就要将原来的实边上的值给异或进去,将原来虚边上的要变成实边的值给亦或出来,然后pushup给结点继承对应的关系式。

1
4 8
1 1 2
3 2 3
1 2 3
3 1 2
5
2 1 2
4 1 2
5
ans:
YES
YES
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e5 + 7;
inline pair<int, int> PP(int x, int y) { return make_pair(min(x, y), max(x, y)); }
map<pair<int, int>, ll> mp;
int N, Q, c[maxN][2], r[maxN], fa[maxN], num[2], zero_num[2];
ll s[maxN], other[maxN], w[maxN], size[maxN];
inline bool isroot(int x) { return c[fa[x]][0] != x && c[fa[x]][1] != x; }
inline void pushup(int x)
{
    if(!x) return;
    s[x] = s[c[x][0]] ^ s[c[x][1]] ^ w[x] ^ other[x];
}
inline void pushr(int x)
{
    if(!x) return;
    swap(c[x][0], c[x][1]);
    r[x] ^= 1;
}
inline void pushdown(int x)
{
    if(!x) return;
    if(r[x])
    {
        pushr(c[x][0]);
        pushr(c[x][1]);
        r[x] = 0;
    }
}
void Rotate(int x)
{
    int y = fa[x], z = fa[y], k = c[y][1] == x, cop = c[x][k ^ 1];
    if(!isroot(y)) c[z][c[z][1] == y] = x;
    fa[x] = z;
    c[y][k] = cop;
    fa[cop] = y;
    c[x][k ^ 1] = y;
    fa[y] = x;
    pushup(y); pushup(x);
}
int st[maxN];
void Splay(int x)
{
    int y = x, z = 0;
    st[++z] = y;
    while(!isroot(y)) st[++z] = y = fa[y];
    while(z) pushdown(st[z--]);
    while(!isroot(x))
    {
        y = fa[x]; z = fa[y];
        if(!isroot(y)) (c[z][0] == y) ^ (c[y][0] == x) ? Rotate(x) : Rotate(y);
        Rotate(x);
    }
}
void access(int x)
{
    int y = 0;
    while(x)
    {
        Splay(x);
        other[x] ^= s[c[x][1]];
        other[x] ^= s[y];
        c[x][1] = y;
        pushup(x);
        y = x; x = fa[x];
    }
}
void makeroot(int x)
{
    access(x); Splay(x);
    pushr(x);
}
int findroot(int x)
{
    access(x); Splay(x);
    while(c[x][0]) { pushdown(x); x = c[x][0]; }
    Splay(x);
    return x;
}
void split(int x, int y)
{
    makeroot(x);
    access(y); Splay(y);
}
void link(int x, int y)
{
    makeroot(x);
    if(findroot(y) != x)
    {
        other[y] ^= s[x];
        fa[x] = y;
        int old = 0, now = 0;
        if(!s[y]) old++;
        if(!s[x]) old++;
        pushup(y);
        if(!s[y]) now++;
        zero_num[0] = zero_num[0] - old + now;
    }
}
void cut(int x, int y)
{
    makeroot(x);
    int old = 0, now = 0;
    if(!s[x]) old++;
    access(y);
    Splay(y);
    fa[x] = c[y][0] = 0;
    pushup(y);
    if(!s[x]) now++;
    if(!s[y]) now++;
    zero_num[0] = zero_num[0] - old + now;
}
inline void init()
{
    num[0] = num[1] = zero_num[0] = zero_num[1] = N; mp.clear();
    for(int i=1; i<=N; i++)
    {
        r[i] = 0; c[i][0] = c[i][1] = 0; w[i] = s[i] = other[i] = 0;
        size[i] = 1;
    }
}
int main()
{
    int T; scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &N, &Q);
        init();
        int op, u, v, old, now; ll val;
        while(Q--)
        {
            scanf("%d", &op);
            if(op == 1)
            {
                scanf("%d%d", &u, &v);
                link(u, v); num[0] --;
            }
            else if(op == 2)
            {
                scanf("%d%d", &u, &v);
                cut(u, v); num[0] ++;
            }
            else if(op == 3)
            {
                old = now = 0;
                scanf("%d%d", &u, &v);
                val = rand() + 1LL; num[1] --;
                mp[PP(u, v)] = val;
                makeroot(u);
                if(!s[u]) old++;
                w[u] ^= val; pushup(u);
                if(!s[u]) now++;
                makeroot(v);
                if(!s[v]) old++;
                w[v] ^= val; pushup(v);
                if(!s[v]) now++;
                zero_num[0] = zero_num[0] - old + now;
            }
            else if(op == 4)
            {
                old = now = 0;
                scanf("%d%d", &u, &v);
                val = mp[PP(u, v)];
                makeroot(u);
                if(!s[u]) old++;
                w[u] ^= val; pushup(u);
                if(!s[u]) now++;
                makeroot(v);
                if(!s[v]) old++;
                w[v] ^= val; pushup(v);
                if(!s[v]) now++;
                num[1] ++;
                zero_num[0] = zero_num[0] - old + now;
            }
            else
            {
                if(num[0] == num[1] && zero_num[0] == num[0]) printf("YES\n");
                else printf("NO\n");
            }
        }
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
void DFSTraverse(Graph graph) { for (int i = 1; i <= graph->vexnum; i++) visited[i] = false; for (int i = 1; i <= graph->vexnum; i++) { if (!visited[i]) DFS(graph, i); } } void DFS(Graph graph, int v) { visited[v] = true; cout << graph->list[v].data << " "; Node* header = graph->list[v].head; while (header) { if (!visited[header->vex]) { DFS(graph, header->vex); } header = header->next; } } void BFSTraverse(Graph graph) { queue<int> MyQueue; for (int i = 1; i <= graph->vexnum; i++) visited[i] = false; for (int i = 1; i <= graph->vexnum; i++) { if (!visited[i]) { visited[i] = true; cout << graph->list[i].data << " "; MyQueue.push(i); while (!MyQueue.empty()) { int front = MyQueue.front(); MyQueue.pop(); Node* header = graph->list[front].head; while (header) { if (!visited[header->vex]) { visited[header->vex] = true; cout << graph->list[header->vex].data << " "; MyQueue.push(header->vex); } header = header->next; } } } } } void printGraph(Graph graph) { int** arr = new int* [graph->vexnum + 1]; for (int i = 1; i <= graph->vexnum; i++) { arr[i] = new int[graph->vexnum + 1]; } for (int i = 1; i <= graph->vexnum; i++) { for (int j = 1; j <= graph->vexnum; j++) { arr[i][j] = 0; } } for (int i = 1; i <= graph->vexnum; i++) { Node* header = graph->list[i].head; while (header) { arr[i][header->vex] = header->weight; header = header->next; } } for (int i = 1; i <= graph->vexnum; i++) { for (int j = 1; j <= graph->vexnum; j++) { cout << arr[i][j] << " "; } cout << endl; } }代码讲解
06-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值