就是选择两个数找第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!