Loj#510-「LibreOJ NOI Round #1」北校门外的回忆【线段树】

1|0正题

题目链接:https://loj.ac/p/510


1|1题目大意

给出一个代码

function add(x,v) while x <= n do s[x] = s[x] xor v x = x + lowbit(x) //注意,这里是 lowbit,这也是两份代码唯一的区别 end while end function function query(x) ans = 0 while x > 0 do ans = ans xor s[x] x = x - lowbit(x) end while return ans end function

其中lowbit(x)表示xK进制下最低非零位的值。

现在给出n,q,Kq次调用add(x,v)或者query(x)

要求输出每次query(x)调用的值。

1n109,2q,K2×105


1|2解题思路

注意到询问的时候我们是可以一位一位的做的,主要是修改的时候。

我们先默认最低非零位就是个位,那么相当于每次x=x+x%K直到x|K,如果只考虑个位的情况,也可以视为每次x=2x%K

首先每个数只有两种到达它的情况,一个是x2,另一个是x+K2,那么如果K是奇数的话,这两个中恰好有一个是整数,也就是每个数字的入边都是1,出边也是1,所以最终图肯定会形成若干个环。

那么考虑K不是奇数的情况,如果x2质因子个数不少于K的,那么它们则可以表示为x2pK2p,这样的话K又是奇数了,也会构成环。

否则x一直乘二直到质因子个数不少于K,也就是说这种情况走不超过logK步就一定能到达一个环或者0

那么我们就是先分位计算,最低位不在环上就暴力跳,在环上就考虑维护。

现在主要是环上怎么维护的问题,同一个最低位上,对于一个修改xy(个位是y,剩下的位是x),会影响一个询问xy的条件。

我们需要找到一个不关于这些点的个位的条件,那么我们就考虑对于每个环定义一个点作为环头,然后所有的操作询问都移动到环头上搞。

然后我们把每个修改拆成修改位置到环头一段和从环头开始不停绕环的一段,

那么第一个的一个限制是询问位置要在它后面并且它们都反着退到环头后值相等,可以用线段树维护位置关系。

第二个先把询问倒着移动到环头,那么限制就是它们对于环上进位次数和的余数相等并且询问的值大于修改的值,可以用权值线段树维护。

时间复杂度:O(Klog2n)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<map> #define mp(x,y) make_pair(x,y) using namespace std; const int N=2e5+10,M=N<<7; int n,q,K,cnt,lg[N],id[N],sum[N],noe[N],dis[N],len[N]; map<pair<int,int> ,int>rt[40],Rt[40]; map<int,int> g; struct SegTree{ int cnt,w[M],ls[M],rs[M]; void Change(int &x,int L,int R,int pos,int val){ if(pos<L||pos>R)return; if(!x)x=++cnt;w[x]^=val; if(L==R)return;int mid=(L+R)>>1; if(pos<=mid)Change(ls[x],L,mid,pos,val); else Change(rs[x],mid+1,R,pos,val); return; } int Ask(int x,int L,int R,int l,int r){ r=min(r,R);l=max(l,L); if(l>r||!w[x])return 0; if(L==l&&R==r)return w[x]; int mid=(L+R)>>1; if(r<=mid)return Ask(ls[x],L,mid,l,r); if(l>mid)return Ask(rs[x],mid+1,R,l,r); return Ask(ls[x],L,mid,l,mid)^Ask(rs[x],mid+1,R,mid+1,r); } }T; void dfs(int x,int pos,int one,int fr){ if(id[x]){sum[fr]=one;return;} noe[x]=one;id[x]=fr;dis[x]=pos;len[fr]++; dfs(x*2%K,pos+1,one+(x*2>=K),fr); return; } int main() { scanf("%d%d%d",&n,&q,&K); for(int i=1;i<=K;i++) if(i%2==0)lg[i]=lg[i/2]+1; for(int i=1;i<K;i++) if(lg[i]>=lg[K]&&!id[i]) ++cnt,dfs(i,0,0,cnt); while(q--){ int op;scanf("%d",&op); if(op==1){ int x,w,i=0,pw=1; scanf("%d%d",&x,&w); while(x*pw<=n){ int p=x%K,y=x/K; while(p&&x*pw<=n){ if(lg[p]>=lg[K]){ T.Change(rt[i][mp(id[p],y-noe[p])],0,len[id[p]]-1,dis[p],w); T.Change(Rt[i][mp(id[p],(y-noe[p]+sum[id[p]])%sum[id[p]])],0,n/pw/K,y+sum[id[p]]-noe[p],w); x=0;break; } else g[x*pw]^=w,x+=x%K,p=x%K,y=x/K; } if(!x||x*pw>n)break; x=x/K;pw=pw*K;i++; } } else{ int x;scanf("%d",&x); int i=0,pw=1,ans=0; while(x){ int p=x%K,y=x/K; if(p!=0){ if(lg[p]>=lg[K]){ ans^=T.Ask(rt[i][mp(id[p],y-noe[p])],0,len[id[p]]-1,0,dis[p]); ans^=T.Ask(Rt[i][mp(id[p],(y-noe[p]+sum[id[p]])%sum[id[p]])],0,n/pw/K,0,y-noe[p]); } else ans^=g[x*pw]; } x/=K;i++;pw=pw*K; } printf("%d\n",ans); } } return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/16477179.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(40)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2021-07-14 jzoj7175-[2021.07.14NOI模拟]种蘑菇(mushroom)【莫比乌斯反演,树形dp】
2021-07-14 P7726-天体探测仪(Astral Detector)【构造】
点击右上角即可分享
微信分享提示