1. 程式人生 > >平凡的測試數據

平凡的測試數據

每次 題目 連接 iostream 特殊 ring 一個點 說了 意思

【題目描述】

樹鏈剖分可以幹什麽?

“可以支持在樹中快速修改一個點信息,快速詢問一條鏈信息”

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;
}

平凡的測試數據