2018 ICPC南京網絡賽 Set(字典樹 + 合併 + lazy更新)

 

 

 題解:n個集合,你要進行m個操作。總共有3種操作。第一種,合併兩個集合x和y。第二張,把特定的集合裏面所有的數字加一。第三種,詢問在某個集合裏面,對於所有數字對2的k次方取模後,有多少個數字等於x。

思路:我們可以對於每一個節點保存一個lazy標記,這個標記類似於線段樹中的lazy標記。每次整個集合增加的時候,只改變lazy標記,然後在下一次訪問這個節點的時候,再去把這個標記push_down。而這個push_down的方式就是按照之前說的那樣,根據lazy的奇偶來判斷是否應該交換兒子和額外進位。對於每一個查詢操作,我們直接把放到字典樹中,確定一個位置,輸出對應節點的size即可。具體操作的時候還要注意,一定要把每一個插入的數字固定插入長度設置爲30,因爲數字的高位即使爲0也是需要保存的。

 

參考代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=1e6+10;
const int depth=31;

struct Trie{
    #define ls T[x].ch[0]
    #define rs T[x].ch[1]
    int tot;
    struct Node{
        int siz,ch[2],tag;
    } T[maxn<<5];
    void Init(){tot=0;}
    int NewNode(){memset(&T[++tot],0,sizeof(T[0]));return tot;}

    void pushdown(int x)
    {
        int lz=T[x].tag;
        if(lz&1){swap(ls,rs);T[ls].tag++;}
        T[ls].tag+=lz/2; T[rs].tag+=lz/2;
        T[x].tag=0;
    }

    void Insert(int &rt,int x)
    {
        int o=rt?rt:rt=NewNode(),c;
        for(int i=0;i<depth;++i)
        {
            c=x&1; x>>=1; T[o].siz++;
            if(T[o].tag) pushdown(o);
            if(!T[o].ch[c]) T[o].ch[c]=NewNode();
            o=T[o].ch[c];
        }
    }

    int query(int rt,int x,int y)
    {
        int o=rt;
        for(int k=0;k<y;++k)
        {
            if(T[o].tag) pushdown(o);
            o=T[o].ch[x&1];x>>=1;if(!o) break;
        }
        return T[o].siz;
    }

    void Merge(int x,int y)
    {
        T[x].siz+=T[y].siz;
        if(T[x].tag) pushdown(x);
        if(T[y].tag) pushdown(y);
        for(int i=0;i<2;++i)
        {
            if(T[x].ch[i]&&T[y].ch[i]) Merge(T[x].ch[i],T[y].ch[i]);
            if(!T[x].ch[i]&&T[y].ch[i]) T[x].ch[i]=T[y].ch[i];
        }
    }
} trie;

int n,m,rt[maxn],f[maxn];

int find(int x)
{
    return f[x]==x?x:f[x]=find(f[x]);
}

int main()
{
    while(~scanf("%d",&n))
    {
        scanf("%d",&m);
        memset(rt,0,sizeof rt);
        trie.Init();
        for(int i=1;i<=n;i++)
        {
            f[i]=i;
            int x;scanf("%d",&x);
            trie.Insert(rt[i],x);
        }
        while(m--)
        {
            int op,x,y,z;
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d%d",&x,&y);
                x=find(x); y=find(y);
                if(x!=y) trie.Merge(rt[x],rt[y]),f[y]=x;
            }
            if(op==2)
            {
                scanf("%d",&x);
                trie.T[rt[find(x)]].tag++;
            }
            if(op==3)
            {
                scanf("%d%d%d",&x,&y,&z);
                x=find(x);
                printf("%d\n",trie.query(rt[x],z,y));
            }
        }
    }
    return 0;
}
View Code

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章