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=;bool fl=false;
while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*+numb);
(fl==true)&&(x=-x);
}
template<class T>il void output(T x){if(x/)output(x/);putchar(x%+'');}
template<class T>il void ot(T x){if(x<) 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+;
ll k,a[N];
int b[][N],num[];
ll ans;
struct tr{
int ls,rs;
int l,r;
void init(){
ls=rs=l=r=;
}
void up(int ll,int rr){
l=ll;r=rr;
}
int sz(){
if(l&&r) return r-l+;
return ;
}
}t[][N];
int tot[];
int n;
pii s[][N];
int q[];
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[][++num[]]=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^;
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]+,t[las][x].r);
}
num[now]=t[las][x].r;
}
int main(){
rd(n);rd(k);
int y;ll w;
for(reg i=;i<=n;++i){
rd(y);rd(w);add(y,i,w);
}
dfs(,);
t[][++tot[]].up(,num[]);
num[]=;tot[]=;
build(tot[],);
s[][++q[]]=mk(,);
for(reg d=;d>=;--d){
ll con=;
int las=tmp;
int now=tmp^;
for(reg i=;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()*+
(ll)t[now][t[las][s[las][i].fi].rs].sz()*t[now][t[las][s[las][i].se].rs].sz()*;
}
}
// cout<<" con "<<con<<endl;
if(k>con){//
k-=con;
ans+=(1LL<<d);
q[now]=;
for(reg i=;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]=;
for(reg i=;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^=;
if(d){
swap(now,las);
tot[now]=;
num[now]=;
for(reg i=;i<=tot[las];++i){
build(i,d-);
}
}
}
ot(ans);
return ;
} }
signed main(){
Miracle::main();
return ;
} /*
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=;bool fl=false;
while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*+numb);
(fl==true)&&(x=-x);
}
template<class T>il void output(T x){if(x/)output(x/);putchar(x%+'');}
template<class T>il void ot(T x){if(x<) 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+;
ll k,s,t,v[N];
int n;
int a[N],b[N],ch[N][],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=;i<=n;++i) rd(p),rd(w),v[i]=v[p]^w;
for(reg i=;i<=n;++i) a[i]=b[i]=;
for(reg d=;d>=;--d){
for(reg i=;i<=tot;++i) ch[i][]=ch[i][]=sz[i]=;
tot=s=t=;
for(reg i=;i<=n;++i) sz[a[i]=get(a[i],v[i]>>d&)]++;
for(reg i=;i<=n;++i) s+=sz[ch[b[i]][v[i]>>d&]];
if(s<k) k-=s,t=,ans|=(1LL<<d);
for(reg i=;i<=n;++i) b[i]=ch[b[i]][(v[i]>>d&)^t];
}
ot(ans);
return ;
} }
signed main(){
Miracle::main();
return ;
} /*
Author: *Miracle*
*/

tql!

CF1055F Tree and XOR的更多相关文章

  1. 解题:CF1055F Tree and XOR

    题面 树上路径是可以通过到根的路径和LCA差出来的,所以建立一棵Trie树按位贪心即可......吗? 发现空间并不够,需要我们每层现建,要记录每个数和它异或答案之后在这一层插进去的编号 #inclu ...

  2. [atAGC052F]Tree Vertices XOR

    结论 注意到如果$x$周围有偶数个1,对$x$操作显然不会改变$a_{x}$,因此不妨强制操作的点周围要有奇数个1,不难发现此时恰好会改变该点,即令$a_{x}=a_{x}\oplus 1$ 称$\{ ...

  3. [atAGC052B]Tree Edges XOR

    定义两点的距离$d(x,y)$为$x$到$y$路径上边权异或和,则两棵树相同当且仅当$\forall 1\le i\le n$,$d(1,i)$相同 新建一个节点0,连边$(0,1)$,初始权值为0, ...

  4. bzoj2006 [NOI2010]超级钢琴 (及其拓展)

    bzoj2006 [NOI2010]超级钢琴 给定一个序列,求长度在 \([L,\ R]\) 之间的区间和的前 \(k\) 大之和 \(n\leq5\times10^5,\ k\leq2\times1 ...

  5. CF241B Friends

    CF241B Friends 和Tree and Xor思路一样CF1055F Tree and XOR 直接找到第k大val,可以直接建出trie,然后按位贪心 考虑比val大的数的和 还是用b[i ...

  6. BZOJ3282: Tree

    传送门 又是权限题= =,过了NOIp我就要去当一只权限狗! LCT裸题,get到了两个小姿势. 1.LCA操作应该在access中随时updata 2.Link操作可以更简单 void Link(i ...

  7. luogu P2574 XOR的艺术 (线段树)

    luogu P2574 XOR的艺术 (线段树) 算是比较简单的线段树. 当区间修改时.\(1 xor 1 = 0,0 xor 1 = 1\)所以就是区间元素个数减去以前的\(1\)的个数就是现在\( ...

  8. 1014: [JSOI2008]火星人prefix - BZOJ

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...

  9. Mail.Ru Cup 2018 Round 2 Solution

    A. Metro Solved. 题意: 有两条铁轨,都是单向的,一条是从左往右,一条是从右往左,Bob要从第一条轨道的第一个位置出发,Alice的位置处于第s个位置,有火车会行驶在铁轨上,一共有n个 ...

随机推荐

  1. 利用Factory-boy来生成实例数据

    库和版本:Faker==2.0.0factory-boy==2.12.0 官方文档:https://factoryboy.readthedocs.io/en/latest/index.html 1. ...

  2. 自定义View系列教程01--常用工具介绍

    站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Android多分辨率适配框架(3)- 使用指南 自定 ...

  3. 【巨人的步伐以及人类的进击】BSGS algorithm

    原问题 求ax≡b(mod p)的最小正整数解. 解法 实际上是以空间换取时间的算法. 先用散列表把 ai (i∈[0,p√)) 都储存起来. 然后再从小到大枚举 j (j∈[0,p√)) ,在散列表 ...

  4. 信息摘要算法 MessageDigestUtil

    package com.xgh.message.digest.test; import java.math.BigInteger; import java.security.MessageDigest ...

  5. es6中的(=>)箭头函数

    x => x * x 上面的箭头函数相当于: function (x) { return x * x; } 箭头函数相当于匿名函数,并且简化了函数定义. 箭头函数有两种格式,一种像上面的,只包含 ...

  6. 【Leetcode链表】奇偶链表(328)

    题目 给定一个单链表,把所有的奇数节点和偶数节点分别排在一起.请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性. 请尝试使用原地算法完成.你的算法的空间复杂度应为 O(1 ...

  7. Mac终端打开AndroidStudio已创建模拟器

    目的 偶尔我们只是想运行模拟器,并不想打开AndroidStudio,这时我们可以从终端找到emulator,通过emulator来启动指定名称的模拟器 步骤 1.找到emulator所在位置 fin ...

  8. 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组

    2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...

  9. thinkphp5.0 路由规则配置

    开启路由‘url_route_on’ => true 首页路由'/' =>'home/index/index' 其它路由(1)'route' => 'home/index/route ...

  10. 一个 PHP 面试题

    一个 PHP 面试题 $i = 0; $j =1; if ($i = 5 || ($j =6)) {echo $i,$j++;} 拿来当面试题不错. 实际并不会这样用,但这个题可以考基础.