zoukankan      html  css  js  c++  java
  • CF1055F Tree and XOR

    CF1055F Tree and XOR

    就是选择两个数找第k大对儿

    第k大?二分+trie上验证

    O(nlognlogn)

    直接按位贪心

    维护可能的决策点(a,b)表示可能答案的对儿在a和b的子树中选择

    所有可能决策点都贡献这一位是0,看是否<=k

    然后更新出下一层的决策点

    但是空间太小,

    所以要滚动

    我的方法:

    维护trie节点和控制区间,维护每个区间的元素,维护决策点

    注意,(a,b)(b,a)算两个。考虑a!=b时候贡献*=2

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    #define pb push_back
    #define solid const auto &
    #define enter cout<<endl
    #define pii pair<int,int>
    // #define int long long 
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=1e6+5;
    ll k,a[N];
    int b[2][N],num[2];
    ll ans;
    struct tr{
        int ls,rs;
        int l,r;
        void init(){
            ls=rs=l=r=0;
        }
        void up(int ll,int rr){
            l=ll;r=rr;
        }
        int sz(){
            if(l&&r) return r-l+1;
            return 0;
        }
    }t[2][N];
    int tot[2];
    int n;
    pii s[2][N];
    int q[2];
    struct node{
        int nxt,to;
        ll val;
    }e[N];
    int hd[N],cnt;
    void add(int x,int y,ll z){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;e[cnt].val=z;
        hd[x]=cnt;
    }
    void dfs(int x,ll dis){
        b[0][++num[0]]=x;a[x]=dis;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            dfs(y,dis^e[i].val);
        }
    }
    int tmp;
    void build(int x,int d){
        int las=tmp,now=tmp^1;
        int bc=t[las][x].r;
        for(reg i=t[las][x].l;i<=t[las][x].r;++i){
            if(!(a[b[las][i]]&(1LL<<d))){
                b[now][++num[now]]=b[las][i];
            }else{
                b[now][bc--]=b[las][i];
            }
        }
        if(num[now]>=t[las][x].l){
            ++tot[now];
            t[las][x].ls=tot[now];
            t[now][tot[now]].init();
            t[now][tot[now]].up(t[las][x].l,num[now]);
        }
        if(num[now]<t[las][x].r){
            ++tot[now];
            t[las][x].rs=tot[now];
            t[now][tot[now]].init();
            t[now][tot[now]].up(num[now]+1,t[las][x].r);
        }
        num[now]=t[las][x].r;
    }
    int main(){
        rd(n);rd(k);
        int y;ll w;
        for(reg i=2;i<=n;++i){
            rd(y);rd(w);add(y,i,w);
        }
        dfs(1,0);
        t[0][++tot[0]].up(1,num[0]);
        num[1]=0;tot[1]=0;
        build(tot[0],61);
        s[0][++q[0]]=mk(1,1);
        for(reg d=61;d>=0;--d){
            ll con=0;
            int las=tmp;
            int now=tmp^1;
            for(reg i=1;i<=q[las];++i){
                if(s[las][i].fi==s[las][i].se){
                    con+=(ll)t[now][t[las][s[las][i].fi].ls].sz()*t[now][t[las][s[las][i].se].ls].sz()+
                    (ll)t[now][t[las][s[las][i].fi].rs].sz()*t[now][t[las][s[las][i].se].rs].sz();
                }else{
                    con+=(ll)t[now][t[las][s[las][i].fi].ls].sz()*t[now][t[las][s[las][i].se].ls].sz()*2+
                    (ll)t[now][t[las][s[las][i].fi].rs].sz()*t[now][t[las][s[las][i].se].rs].sz()*2;
                }
            }
            // cout<<" con "<<con<<endl;
            if(k>con){//1
                k-=con;
                ans+=(1LL<<d);
                q[now]=0;
                for(reg i=1;i<=q[las];++i){
                    if(t[las][s[las][i].fi].ls&&t[las][s[las][i].se].rs){
                        s[now][++q[now]]=mk(t[las][s[las][i].fi].ls,t[las][s[las][i].se].rs);
                    }
                    if(s[las][i].fi!=s[las][i].se){
                        if(t[las][s[las][i].fi].rs&&t[las][s[las][i].se].ls){
                            s[now][++q[now]]=mk(t[las][s[las][i].fi].rs,t[las][s[las][i].se].ls);
                        }
                    }
                }
            }else{
                q[now]=0;
                for(reg i=1;i<=q[las];++i){
                    if(t[las][s[las][i].fi].ls&&t[las][s[las][i].se].ls){
                        s[now][++q[now]]=mk(t[las][s[las][i].fi].ls,t[las][s[las][i].se].ls);
                    }
                    if(t[las][s[las][i].fi].rs&&t[las][s[las][i].se].rs){
                        s[now][++q[now]]=mk(t[las][s[las][i].fi].rs,t[las][s[las][i].se].rs);
                    }
                }
            }
            tmp^=1;
            if(d){
                swap(now,las);
                tot[now]=0;
                num[now]=0;
                for(reg i=1;i<=tot[las];++i){
                    build(i,d-1);
                }
            }
        }
        ot(ans);
        return 0;
    }   
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
    */

    然后这个代码又臭又长

    一个很nb的写法:

    1.首先不用建树,p<=i,直接v[i]=v[p]^w,一行搞定

    2.不用维护决策两个点,只用维护每个元素,可能匹配的子树节点位置!以及自己的权值属于的位置

    3.每次更新节点的size和a,s和k比较大小

    4.更新b,

    也根本不用0/1滚动,b和a数组已经区分了位置。

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    #define pb push_back
    #define solid const auto &
    #define enter cout<<endl
    #define pii pair<int,int>
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=1e6+5;
    ll k,s,t,v[N];
    int n;
    int a[N],b[N],ch[N][2],sz[N];
    int tot;
    ll ans;
    int get(int x,int c){
        return ch[x][c]?ch[x][c]:ch[x][c]=++tot;
    }
    int main(){
        rd(n);rd(k);int p;ll w;
        for(reg i=2;i<=n;++i) rd(p),rd(w),v[i]=v[p]^w;
        for(reg i=1;i<=n;++i) a[i]=b[i]=1;
        for(reg d=61;d>=0;--d){
            for(reg i=1;i<=tot;++i) ch[i][0]=ch[i][1]=sz[i]=0;
            tot=s=t=0;
            for(reg i=1;i<=n;++i) sz[a[i]=get(a[i],v[i]>>d&1)]++;
            for(reg i=1;i<=n;++i) s+=sz[ch[b[i]][v[i]>>d&1]];
            if(s<k) k-=s,t=1,ans|=(1LL<<d);
            for(reg i=1;i<=n;++i) b[i]=ch[b[i]][(v[i]>>d&1)^t];
        }
        ot(ans);
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
    */

    tql!

  • 相关阅读:
    LINQ表达式预备讲课
    开发中必须安装的软件
    jquery判断单选按钮radio是否选中的方法
    JQuery判断radio(单选框)是否选中和获取选中值方法总结
    jquery $.each 和for怎么跳出循环终止本次循环
    ECharts 3.0 初学感想及学习中遇到的瓶颈
    js 日期时间大小比较
    Vue资料-简介-旋之华
    vue 引用 vue-resource步骤 (遇错排解)
    vue-resource和axios的简单使用方法总结
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10873715.html
Copyright © 2011-2022 走看看