平凡的测试数据

【题目描述】

树链剖分可以干什么?

“可以支持在树中快速修改一个点信息,快速询问一条链信息”

LCT可以干什么?

“可以支持树链剖分支持的特性,并且支持快速链接两个棵树,或者断开某条边”

那我现在要出一道关于树的题目,一开始有n个点,每个点自成一颗树,所以现在有n棵树。每个点有一个权值。有以下这些操作类型:

连接操作:1 a b,连接a和b,使a成为b的儿子结点,a一定是某个树的根节点。这样就把两个数连接到一起,此时a以及所有后代的根节点均为b所在树的根节点。

询问操作:2 a,询问a到自己所在树的根节点所有在路径(包括自己和根节点)上的所有点的权值的异或和。

恩...但是由于我懒,所以还没有造数据,请你帮我写个标程让我用来造数据吧。

 

【输入格式】

第一行两个整数n和m,表示有n个点和m个操作。

接下有一行n个整数,第i个整数表示第i个点的权值。

接下来m行,每行为三个整数1 a b,或者2 a。

如果是1 a b表示这是一个连接操作,意义见题目。

如果是2 a表示这是一个询问操作,意义见题目。

 

【输出格式】

对于每个询问操作,输出一行,表示从a到根节点路径上所有点的权值的异或和。

 

【样例输入】

5 8 1 2 3 4 5 2 2 1 2 1 2 2 1 4 3 1 3 2 2 3 1 5 1 2 5

 

【样例输出】

2 3 0 4

 

【提示】

样例解释

样例中每个节点权值与标号相同

第一个询问中2的根节点是自己,所以第一个询问2节点的答案为0

第二个询问中2的根节点是1,路径为2-1,所以答案为2 xor 1 = 3

第三个询问中3到根节点的路径为3-2-1,所以答案为3 xor 2 xor 1 = 0

第四个询问中5到根节点的路径为5-1,所以答案为5 xor 1 = 4

数据范围

对于40%的数据1 <= n,m <= 1000

对于90%的数据1 <= n <= 100000, 1 <= m <= 200000

对于100%的数据1 <= n <= 300000, 1 <= m <= 500000

所有节点的权值均为正整数且在int范围内

 

【题解】

       我向往已久的带权并查集,果然非常有意思,甚至要远超银河英雄传说了。因为亦或和只是到父亲的路径上的,所以在路径压缩的同时就可以维护。每次合并则把接头处亦或一下;每次路径压缩都合并一下自身和父亲的亦或和,再亦或一下父亲去重(利用了两次亦或变回1的性质),这就是维护并查集附加信息的特殊操作了。查询时再find一次,确保输出的是最新结果。对并查集有特殊的偏爱,特别是带权并查集,我还惦记着食物链和奇偶游戏呐。

 

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int sj=300010;
int n,m,fa[sj],a[sj],a1,a2,nn;
long long yh[sj];
bool cl[sj];
int find(int x)
{
    if(fa[x]==x) return x;
    int temp=find(fa[x]);
    yh[x]=a[fa[x]]^yh[x]^yh[fa[x]];
    fa[x]=temp;
    return fa[x];
}
void hb(int x,int y)
{
     yh[x]=a[x]^yh[y];
     y=find(y);
     fa[x]=y;
}
int main()
{
    //freopen("t.txt","r",stdin);
    freopen("td.in","r",stdin);
    freopen("td.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    { 
       scanf("%d",&a[i]);
       fa[i]=i;
       yh[i]=a[i];
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&nn,&a1);
        if(nn==1)
        {
           scanf("%d",&a2);
           hb(a1,a2);
        }
        if(nn==2)
        {
           find(a1);
           printf("%lld\n",yh[a1]);
        }
    }
    //while(1);
    return 0;
}

 

转载于:https://www.cnblogs.com/moyiii-/p/7241557.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值