zoukankan      html  css  js  c++  java
  • COGS 2089. 平凡的测试数据

    【题目描述】


    树链剖分可以干什么?

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

    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范围内

    题解:

      带权并查集,考试的时候没想出出来,真是脑抽,为什么可以用并查集呢?因为他只要维护路径上的总和,并且刚好也只有合并和查询两个操作,不过主要还是因为只有维护路径上的信息。

      具体怎么做?可以考虑将点权付给边权。记s[i]表示i节点到根节点的亦或合,然后每次合并两棵树时只要将被合并的点的点权付给边权即s[x]=quan[x];(quan[x]是点权),合并路径是只要将两段路径抑或起来就可以了。即s[now]=s[now]^s[fa[now]],最后因为是边权,没有算根节点,输出答案时在亦或一下就可以了。

    代码:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #define ll long long
    #define MAXN 100010
    #define MAXN2 500000
    using namespace std;
    int quan[MAXN2*2],s[MAXN2*2],fa[MAXN2*2];
    int n,m,num=0,hhh;
    
    
    int find(int now){
        if(fa[now]!=now) hhh=find(fa[now]);
        else hhh=fa[now];
        s[now]=s[now]^s[fa[now]];
        fa[now]=hhh;
        return fa[now];
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) {
            scanf("%d",&quan[i]);
            fa[i]=i;
        }
        for(int i=1;i<=m;i++){
            int id,x,y;
            scanf("%d",&id);
            if(id==2){
                scanf("%d",&x);
                int hh=find(x);
                printf("%d
    ",s[x]^quan[hh]);
            }
            else{
                scanf("%d%d",&x,&y);
                fa[x]=y;
                s[x]=quan[x];
            }
        }
        return 0;
    }
  • 相关阅读:
    VFP正则表达式判断是否是手机号码/电子邮件
    VFP自定义函数StringFormat (仿.NET String.Format 方法)
    解决SOAPCLIENT访问WebSerivce外网发布端口
    VFP调用SOAPTOOLKIT 低级API
    经典的Hello World VFP前端调后端C# Webservice
    VFP不同句柄 同一事务处理 统一提交或回滚
    C++文件(夹)选择对话框操作
    Linxu之rz和sz命令
    测试标题
    自定义Silverlight TextBox 具有下拉框提示控件
  • 原文地址:https://www.cnblogs.com/renjianshige/p/7412095.html
Copyright © 2011-2022 走看看