题目大意

有\(n\)(\(n\leq5\times10^5\))个数\(a_1,a_2,...a_n\)(\(a_i\leq 2^{32}-1\))

求区间异或和前\(k(k\leq2\times10^5)\)大之和

题解

考虑二分,找出第\(k\)大异或和是多少

将每个位置上的数变成前缀异或和\(s_i\)后,建出可持久化trie树,第\(i\)个版本由\(0,s_1,s_2,..,s_i\)组成,trie树上每个点维护这个点的子树中有几个数

二分\(x\),判断是否有不超过\(k\)个异或和

发现这样时间复杂度为\(\Theta(n\times log^2 a)\),略多

发现一般情况下在线段树上二分时都不是先二分出一个值再查询,而是在线段树上边走边计算

同理,本题就可以维护\(n\)个位置,即当前走到的第\(i(i\in[1,n])\)个版本的trie树的位置

每次判断当前位放1会不会使大于等于当前值的异或和数量少于\(k\),会就走\(a_i\)当前位异或0的方向,反之就走\(a_i\)当前位异或1的方向

算出第\(k\)大异或和后,直接在trie树中dfs找出大于(注意,不能找等于它的,不然会找多)它的异或和,计入答案,顺便记一共加了几个数

\((k-上一步加的数的个数)\)就是等于第\(k\)大异或和的异或和的个数,把这个计入答案

以上两步中走到的点只有大于第\(k\)大异或和的点和它们的父亲,只有\(\Theta(k\times log\space a)\)

总时间复杂度\(\Theta((n+k)\times log\space a)\)

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 500003
#define maxnd (maxn*33)
#define LL long long
#define int LL
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(LL x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
LL ans,a[maxn],num;;
const int len=31;
int n,k,ch[maxnd][2],val[maxnd],rt[maxn],cntnd,now[maxn],nownum;
void ext(int i)
{
int u,nu=++cntnd;rt[i]=cntnd;
if(i)u=rt[i-1];
else u=0;
dwn(j,len,0)
{
int d=(a[i]&(1ll<<j))>>j;
if(u)val[nu]=val[u]+1,ch[nu][d^1]=ch[u][d^1],u=ch[u][d];
else val[nu]=1;
ch[nu][d]=++cntnd,nu=cntnd;
}
if(u)val[nu]=val[u]+1;
else val[nu]=1;
}
void getans(int u,LL ai,LL xi)
{
if(!ch[u][0]&&!ch[u][1]){if(((LL)ai^(LL)xi)>(LL)num){nownum+=val[u],ans=ans+(LL)((LL)ai^(LL)xi)*val[u];}return;}
if(ch[u][0])getans(ch[u][0],ai,xi<<1);
if(ch[u][1])getans(ch[u][1],ai,xi<<1|1);
return;
}
#define dd(x,y) ((x&(1ll<<y))>>y)
signed main()
{
n=read(),k=read();
rep(i,1,n)a[i]=read()^a[i-1];
rep(i,0,n)ext(i),now[i]=rt[i];
dwn(i,len,0)
{
int tmp=0;
rep(j,1,n)if(now[j]){tmp+=val[ch[now[j]][dd(a[j],i)^1ll]];}
if(tmp+nownum>=k){rep(j,1,n)if(now[j])now[j]=ch[now[j]][dd(a[j],i)^1ll];num=num<<(1ll)|(1ll);}
if(tmp+nownum<k){rep(j,1,n)if(now[j])now[j]=ch[now[j]][dd(a[j],i)];nownum+=tmp;num=num<<(1ll);}
}
nownum=0;
rep(i,1,n)
{
int u=rt[i],vv=0;
dwn(j,len,0)
{
int d=dd(a[i],j),e=dd(num,j);
if(!e&&ch[u][d^1]){getans(ch[u][d^1],a[i],vv<<1|(d^1));}
if(!ch[u][d^e])break;
u=ch[u][d^e],vv=vv<<1|(d^e);
}
}
ans+=(LL)num*(k-nownum);
write(ans);
return 0;
}
/*
3 2
1 2 3
*/
一些感想

sb猎人公会nmsl

最新文章

  1. php libevent 扩展使用示例
  2. 爱上MVC~为CheckBoxFor和RadioButtonFor加个扩展方法吧(希望MVC5把这方法收纳——呵呵)
  3. java 访问sql server数据库
  4. Java 基础【11】@注解
  5. ADB 常用命令总结(持续更新)
  6. Js 与 TextArea
  7. HDU 1698 Just a Hook 区间更新 lazy标记
  8. HDOJ/HDU 2562 奇偶位互换(交换位置~)
  9. 《Clean Code》重点内容总结
  10. http://begin.lydsy.com/JudgeOnline/problem.php?id=2774(poi病毒)
  11. pyhton安装pillow问题解决
  12. 51Nod 1284 2 3 5 7的倍数 容斥原理
  13. 今天才知道原来我还没弄清楚js中全局变量和局部变量的定义...
  14. 记一次shell脚本编写及执行
  15. ArrayList、LinkedList、Vector的区别。
  16. SSH Secure Shell Client安装和使用
  17. Spiral Matrix leetcode java
  18. shell curl 下载图片并另存为(重命名)
  19. .Net高级技术——IDisposable
  20. Java的Calendar类

热门文章

  1. 启动weblogic域不需要输入密码设置方法
  2. win7 32 c++环境
  3. Redis Sentinel 情况下bind地址设置
  4. java性能监控工具jstat-windows
  5. 怎样高效利用GitHub(非常多资料可供下载)
  6. nightwatch.js - scroll until element is visible
  7. idea主要设置大纲图
  8. Android Studio 那些事|Activity文件前标识图标显示为 j 而是 c
  9. 使用mark-sweep算法的垃圾回收器
  10. dwr框架中DWRUtil的方法