• [bzoj4763]雪辉&[bzoj4812][Ynoi2017]由乃打扑克


    来自FallDream的博客,未经允许,请勿转载,谢谢。


    cut掉部分题面。

    给一个n个点的树,点有点权,有m次询问,每次询问多条链的并有多少种不同的点权以及它的mex
    mex就是一个集合中最小的没有出现的非负整数,注意0要算
    比如说集合是1,9,2,6,0,8,1,7,则出现了0,1,2,6,7,8,9这7种不同的点权,因为没有3所以mex是3
    n<=100000,总共询问的链数量<=100000 权值<=30000
     
    考虑对树分块,预处理每个块的中心到它父亲中同样是中心的点的bitset,然后查询的时候先暴力跳到中心,再能跳到上一个中心就跳,最后再暴力跳即可。
    手写bitset来查询答案。
    预处理复杂度$nsqrt{n}$,每次询问复杂度是$O(sqrt{n}+frac{30000}{64})$
     
    另一道由乃打扑克也是同样的做法,最后询问的时候,16位可以一起处理,预处理0-65535里面每个数低位连续的1的数量,中间的1在不同幂次下的贡献和高位连续的1的数量。
    雪辉
    #include<iostream>
    #include<cstdio>
    #define MN 100000
    #define MB 320
    #define MD 17
    #define ull unsigned long long
    #define getchar() (*S++)
    char B[1<<26],*S=B;
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    int n,m,flag,w[MN+5],head[MN+5],cnt=0,fa[MD+5][MN+5],mx[MN+5];
    int mark[MN+5],dep[MN+5],rt[MB+5],rtnum=0,top[MN+5],Num[MN+5];
    struct edge{int to,next;}e[MN*2+5];
    ull MAXN=0;
    struct Bitset
    {
        ull s[470];int len;
        void Clear(){for(int i=0;i<470;++i) s[i]=0;len=0;}
        void operator |=(int x){s[x>>6]|=1LL<<(x&63);len=max(len,x>>6);}
        void operator |=(const Bitset&y)
        {
            len=max(len,y.len);
            for(int i=0;i<=len;++i)
                s[i]|=y.s[i];
        }
        int num()
        {
            int res=0;
            for(int i=0;i<=len;++i)
                res+=Num[s[i]>>48]+Num[(s[i]>>32)&65535]+Num[(s[i]>>16)&65535]+Num[s[i]&65535];
            return res;
        }
        int Query()
        {
            for(int i=0;i<470;++i) if(s[i]!=MAXN)
                for(int j=0;j<64;++j)
                    if(!(s[i]&((ull)1<<j)))
                        return i*64+j;
        }
    }b[MB+5][MB+5],ans;
    
    inline void ins(int f,int t)
    {
        e[++cnt]=(edge){t,head[f]};head[f]=cnt;
        e[++cnt]=(edge){f,head[t]};head[t]=cnt;
    }
    
    void init(int x)
    {
        mx[x]=dep[x];
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=fa[0][x])
            {
                fa[0][e[i].to]=x;
                dep[e[i].to]=dep[x]+1;
                init(e[i].to);
                mx[x]=max(mx[x],mx[e[i].to]);
            }
        if(mx[x]-dep[x]>=MB||x==1) mx[x]=0,rt[mark[x]=++rtnum]=x;
    }
    
    inline int lca(int x,int y)
    {
        if(dep[x]<dep[y]) swap(x,y);
        for(int k=dep[x]-dep[y],j=0;k;k>>=1,++j)
            if(k&1) x=fa[j][x];
        if(x==y) return x;
        for(int i=MD;~i;--i)
            if(fa[i][x]!=fa[i][y])
                x=fa[i][x],y=fa[i][y];
        return fa[0][x];
    }
    int last=0;
    int main()
    {
        fread(B,1,1<<26,stdin);
        n=read();m=read();flag=read();
        for(int i=0;i<64;++i) MAXN|=(ull)1<<i;
        for(int i=0;i<=65536;++i)
            for(int j=i;j;j>>=1)
                Num[i]+=(j&1);
        for(int i=1;i<=n;++i) w[i]=read();
        for(int i=1;i<n;++i) ins(read(),read());
        dep[1]=1;init(1);
        for(int i=1;i<=MD;++i)
            for(int j=1;j<=n;++j)
                fa[i][j]=fa[i-1][fa[i-1][j]];
        for(int i=1;i<=rtnum;++i)
        {
            Bitset now;now.Clear();now|=w[rt[i]];b[i][i]=now;
            for(int k=fa[0][rt[i]];k;k=fa[0][k])
            {
                now|=w[k];
                if(mark[k])
                {
                    b[i][mark[k]]=now;
                    if(!top[rt[i]]) top[rt[i]]=k;
                }
            }
        }
        for(int i=1;i<=m;++i)
        {
            ans.Clear();int nn=read();
            for(int j=1;j<=nn;++j)
            {
                int x=read(),y=read(),xx,yy;
                if(flag) x^=last,y^=last;
                int z=lca(x,y);ans|=w[x];ans|=w[y];
                for(;!mark[x]&&dep[x]>dep[z];)
                    x=fa[0][x],ans|=w[x];
                for(;!mark[y]&&dep[y]>dep[z];)
                    y=fa[0][y],ans|=w[y];
                for(xx=x;dep[top[xx]]>=dep[z];xx=top[xx]);
                for(yy=y;dep[top[yy]]>=dep[z];yy=top[yy]);
                ans|=b[mark[x]][mark[xx]];
                ans|=b[mark[y]][mark[yy]];
                for(;xx!=yy;)
                {
                    if(dep[xx]<dep[yy]) swap(xx,yy);
                    xx=fa[0][xx];ans|=w[xx];
                }
            }
            int x=ans.num(),y=ans.Query();
            last=x+y;
            printf("%d %d
    ",x,y);
        }
        return 0;
    }
    View Code

    由乃打扑克

    #include<iostream>
    #include<cstdio>
    #define MN 100000
    #define MB 350
    #define MD 17
    #define int unsigned int
    #define uint  int
    #define ull unsigned long long
    #define getchar() (*S++)
    char B[1<<26],*S=B;
    using namespace std;
    inline long long read()
    {
        long long x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    int n,m,w[MN+5],head[MN+5],cnt=0,fa[MD+5][MN+5],mx[MN+5];
    int mark[MN+5],dep[MN+5],rt[MB+5],rtnum=0,top[MN+5],front[MN+5],back[MN+5];
    uint pw[30005][32],Num[65536][32],K,last=0;
    struct edge{int to,next;}e[MN*2+5];
    
    void Combine(uint&ans,uint&len,int x)
    {
        if(x==65535) {len+=16;return;}
        len+=front[x];ans+=pw[len][K];
        ans+=Num[x][K];len=back[x];
    }
    struct Bitset
    {
        ull s[470];int len;
        void Clear(){for(int i=0;i<470;++i) s[i]=0;len=0;}
        void operator |=(int x){s[x>>6]|=1LL<<(x&63);len=max(len,x>>6);}
        void operator |=(const Bitset&y)
        {
            len=max(len,y.len);
            for(int i=0;i<=len;++i)
                s[i]|=y.s[i];
        }
        uint Query(int k)
        {
            uint ans=0,L=0;
            for(int i=0;i<=len;++i)
                Combine(ans,L,s[i]&65535),
                Combine(ans,L,(s[i]>>16)&65535),
                Combine(ans,L,(s[i]>>32)&65535),
                Combine(ans,L,(s[i]>>48)&65535);
            return (ans+=pw[L][k]);
        }
    }b[MB+5][MB+5],ans;
    
    inline void ins(int f,int t)
    {
        e[++cnt]=(edge){t,head[f]};head[f]=cnt;
        e[++cnt]=(edge){f,head[t]};head[t]=cnt;
    }
    
    void init(int x)
    {
        mx[x]=dep[x];
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=fa[0][x])
            {
                fa[0][e[i].to]=x;
                dep[e[i].to]=dep[x]+1;
                init(e[i].to);
                mx[x]=max(mx[x],mx[e[i].to]);
            }
        if(mx[x]-dep[x]>=MB||x==1) mx[x]=0,rt[mark[x]=++rtnum]=x;
    }
    
    inline int lca(int x,int y)
    {
        if(dep[x]<dep[y]) swap(x,y);
        for(int k=dep[x]-dep[y],j=0;k;k>>=1,++j)
            if(k&1) x=fa[j][x];
        if(x==y) return x;
        for(int i=MD;~i;--i)
            if(fa[i][x]!=fa[i][y])
                x=fa[i][x],y=fa[i][y];
        return fa[0][x];
    }
    
    main()
    {
        fread(B,1,1<<26,stdin);
        n=read();m=read();
        for(int i=1;i<=30000;++i)
        {
            int k=1;pw[i][0]=1;
            for(int j=1;j<=30;++j)
                pw[i][j]=(k*=i);
        }
        
        for(int i=0;i<=65534;++i)
        {
            int j=0,flag=0;
            for(int k=i,kk=1;kk<=16;++kk,k>>=1)
                if(k&1) ++j;
                else
                {
                    if(!flag) flag=1,front[i]=j;
                    else for(int kkk=0;kkk<=30;++kkk)
                        Num[i][kkk]+=pw[j][kkk];
                    j=0;
                }
            back[i]=j;
        }
        for(int i=1;i<=n;++i) w[i]=read();
        for(int i=1;i<n;++i) ins(read(),read());
        dep[1]=1;init(1);
        for(int i=1;i<=MD;++i)
            for(int j=1;j<=n;++j)
                fa[i][j]=fa[i-1][fa[i-1][j]];
        for(int i=1;i<=rtnum;++i)
        {
            Bitset now;now.Clear();now|=w[rt[i]];b[i][i]=now;
            for(int k=fa[0][rt[i]];k;k=fa[0][k])
            {
                now|=w[k];
                if(mark[k])
                {
                    b[i][mark[k]]=now;
                    if(!top[rt[i]]) top[rt[i]]=k;
                }
            }
        }
        for(int i=1;i<=m;++i)
        {
            ans.Clear();int nn=read();
            for(int j=1;j<=nn;++j)
            {
                uint x=(read()^last),y=(read()^last),xx,yy;
                uint z=lca(x,y);ans|=w[x];ans|=w[y];
                if(x<1||x>n||y<1||y>n) return 0;
                for(;!mark[x]&&dep[x]>dep[z];)
                    x=fa[0][x],ans|=w[x];
                for(;!mark[y]&&dep[y]>dep[z];)
                    y=fa[0][y],ans|=w[y];
                for(xx=x;dep[top[xx]]>=dep[z];xx=top[xx]);
                for(yy=y;dep[top[yy]]>=dep[z];yy=top[yy]);
                ans|=b[mark[x]][mark[xx]];
                ans|=b[mark[y]][mark[yy]];
                for(;xx!=yy;)
                {
                    if(dep[xx]<dep[yy]) swap(xx,yy);
                    xx=fa[0][xx];ans|=w[xx];
                }
            }
            printf("%u
    ",last=ans.Query(K=read()));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    推荐一款Notepad++主题Dracula
    一个小工具,利用php把指定目录文件递归上传到阿里云OSS
    svn2个小问题的解决
    借助Algorithmia网站API:用AI给黑白照片上色,复现记忆中的旧时光
    C++@sublime GDB调试
    C++@重载函数
    C++@语句块
    C++@命名空间(转)
    《Linux与Qt程序设计》知识框架
    多线程中的使用共享变量的问题 (转)
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj4763.html
Copyright © 2020-2023  润新知