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('\n');}

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('\n');}

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!

 

posted @ 2019-05-16 09:36  *Miracle*  阅读(402)  评论(0编辑  收藏  举报