【xsy1098】第k小 可持久化trie
题目大意:你要维护一个长度为n的序列,资瓷对整个序列xor,and,or一个数,以及区间第k小查询。
数据范围:n≤50000,所有数字<231。
此题甚妙
我们不难想出没有位运算的区间第k大查询,直接可持久化trie就可以了。
考虑此题只有xor操作。
我们记一个last表示之前所有异或操作的数的异或和。
查询区间第k小时,随便查询下就行了(在比较时假装交换trie的左右子树)
考虑存在or和and操作,我们设对序列操作的数字为x,设vis[k]表示整个序列的第k位是否被全部归零过。
不难发现,and操作对第i位有意义,当且仅当数字x的第i位为0,(or情况类似等下会讲),在这种情况下,对于序列上的所有数,第i位都会归零,(last的第i位也会归零)
同理,or操作对第i位有意义,当且仅当数字x的第i位为1,对于序列上所有数,第i位都会变为1(last的第i位也会变为1)
实际上两个操作本质上是相同的,我们可以用and操作和last|=x去实现or操作。
不难发现,对于数列的每一位,归零操作至多只需要执行一次。
那么,对于每个需要执行归零操作的or或and操作,我们重建一次可持久化trie就可以了。
时间复杂度O(n log2V+m logV)其中V为数列中的最大值。
1 #include<bits/stdc++.h> 2 #define M 50005 3 #define INF 2147483647 4 using namespace std; 5 6 struct trie{int a[2],siz;}a[M*33]={0}; int use=0; 7 void add(int &x,int dep,int zhi){ 8 a[++use]=a[x]; a[x=use].siz++; 9 if(dep==-1) return; 10 bool k=zhi&(1<<dep); 11 if(k) add(a[x].a[1],dep-1,zhi); 12 else add(a[x].a[0],dep-1,zhi); 13 } 14 int num[M]={0},n,m,zhi=0,root[M]={0},vis[32]={0},pls=INF; 15 16 int query(int x,int y,int dep,int K){ 17 if(dep==-1) return 0; 18 bool k=zhi&(1<<dep); 19 int now=a[a[y].a[k]].siz-a[a[x].a[k]].siz,res=1<<dep; 20 if(K<=now) res=query(a[x].a[k],a[y].a[k],dep-1,K); 21 else res+=query(a[x].a[k^1],a[y].a[k^1],dep-1,K-now); 22 return res; 23 } 24 25 void build(){ 26 for(int i=1;i<=n;i++) num[i]=num[i]&pls; 27 use=0; 28 for(int i=1;i<=n;i++){ 29 root[i]=root[i-1]; 30 add(root[i],30,num[i]); 31 } 32 } 33 int main(){ 34 scanf("%d%d",&n,&m); 35 for(int i=1;i<=n;i++) scanf("%d",num+i); 36 build(); 37 while(m--){ 38 char op[4]; int x,l,r,k; pls=INF; 39 scanf("%s",op); 40 if(op[0]=='X'){scanf("%d",&x); zhi^=x;} 41 if(op[0]=='O'){ 42 scanf("%d",&x); 43 for(int i=0;i<=30;i++) 44 if(((1<<i)&x)){ 45 if(vis[i]==0) vis[i]=1,pls^=(1<<i); 46 zhi|=(1<<i); 47 } 48 if(pls==INF) continue; 49 build(); 50 } 51 if(op[1]=='n'){ 52 scanf("%d",&x); 53 for(int i=0;i<=30;i++) 54 if(((1<<i)&x)==0){ 55 if(vis[i]==0) vis[i]=1,pls^=(1<<i); 56 zhi&=(INF-(1<<i)); 57 } 58 if(pls==INF) continue; 59 build(); 60 } 61 if(op[1]=='s'){ 62 scanf("%d%d%d",&l,&r,&k); 63 printf("%d\n",query(root[l-1],root[r],30,k)); 64 } 65 } 66 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!