zoukankan      html  css  js  c++  java
  • 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
    ",trie.query(rt[x],z,y));
                }
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Redis数据模型
    Redis集群使用的一些命令(持续更新)
    Redis简单集群搭建
    观察者模式
    抽象工厂模式
    简单工厂模式及其简单Java案例代码实现
    工厂方法模式及简单Java案例代码实现
    Java中的双重检查锁(double checked locking)
    BayaiM__MYSQL千万级数据量的优化方法积累__初级菜鸟
    BayaiM__Linux安装MySQL的两种方法
  • 原文地址:https://www.cnblogs.com/csushl/p/11449521.html
Copyright © 2011-2022 走看看