Description
给出一段伪代码,其中lowbit(x)表示x在k进制下最低非零位的值,你需要维护这样一个东西,支持这两种操作。
x<=10^9 q,k<=200000
Solution
首先每个点x+lowbit(x)唯一,所以所有的点形成了一棵树
问题变成了链修改单点求
考虑当k为奇数时,所有的操作不会改变x的最低非0位
即所有的点形成了以
(
2
x
+
1
)
k
d
,
(
2
x
+
1
<
k
,
d
>
=
0
)
(2x+1)k^d,(2x+1<k,d>=0)
(2x+1)kd,(2x+1<k,d>=0)开头的一堆链,如果能对每个数找到它所在的开头就做完了
当k为偶数时,考虑将k写成
k
=
2
p
∗
a
k=2^p*a
k=2p∗a,a是奇数,那么可以发现所有的
S
=
2
q
∗
b
S=2^q*b
S=2q∗b,b是奇数且q>=b的S也形成了一堆以
(
2
x
+
1
)
∗
2
p
k
d
,
(
(
2
x
+
1
)
2
p
<
k
,
d
>
=
0
)
(2x+1)*2^pk^d,((2x+1)2^p<k,d>=0)
(2x+1)∗2pkd,((2x+1)2p<k,d>=0)开头的链
对于剩下的点,我们考虑暴力跳到第一个合法的S
注意到对于一个x,如果最低位不变那么只需要跳p次就跳到了,否则就说明有进位产生,而进位最多为
log
k
n
\log_kn
logkn次,所以总次数为
p
∗
log
k
n
=
log
2
k
∗
log
k
n
=
log
2
n
p*\log_kn=\log_2k*\log_kn=\log_2n
p∗logkn=log2k∗logkn=log2n
现在问题就变成了对于一个数找到其对应的开头,考虑最低位不会改变,所以会一直/2直到不能再除,然后就会产生退位
总的退位次数我们是可以计算出来的,对于数x,其最低位为t,那么退位次数为
⌊
x
k
t
⌋
\lfloor {x\over k^t}\rfloor
⌊ktx⌋,直接倍增求出来就行了
复杂度大概是
O
(
q
log
k
n
log
2
n
)
O(q\log_kn\log_2n)
O(qlogknlog2n),由于当k=2时有点跑不过所以特判了。。。。
Code
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int read() {
char ch;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
int x=ch-'0';
for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x;
}
void write(int x) {
if (!x) {puts("0");return;}
char ch[20];int tot=0;
for(;x;x/=10) ch[++tot]=x%10+'0';
fd(i,tot,1) putchar(ch[i]);
puts("");
}
const int N=2e5+5,M=N<<5;
int tr[M],ls[M],rs[M],tot,rt[M];
void modify(int &v,int l,int r,int x,int y) {
if (!v) v=++tot;tr[v]^=y;
if (l==r) return;
int mid=l+r>>1;
if (x<=mid) modify(ls[v],l,mid,x,y);
else modify(rs[v],mid+1,r,x,y);
}
int query(int v,int l,int r,int x,int y) {
if (!v) return 0;
if (x<=l&&r<=y) return tr[v];
int mid=l+r>>1,tmp=0;
if (x<=mid) tmp^=query(ls[v],l,mid,x,y);
if (y>mid) tmp^=query(rs[v],mid+1,r,x,y);
return tmp;
}
int n,q,k,l,p,w,cnt,pw[35],ct[N],g[N][35];
int inv[N];
map<int,int> Id,Val;
int low(int x) {int d=1;for(;!(x%k);x/=k) d++;return d;}
int lowbit(int x) {int d=1;for(;!(x%k);x/=k) d++;return pw[d-1]*(x%k);}
int Lowbit(int x) {for(;!(x%k);x/=k);return x%k;}
int find(int x) {
int t=low(x),s=Lowbit(x),d=t==w?0:x/pw[t];
fd(j,30,1)
while ((1<<j)-1<=d) {
d-=(1<<j)-1;
s=g[s][j];
}
s=g[s][0];
return Id[s*pw[t-1]];
}
void Modify(int x,int v) {
for(;ct[Lowbit(x)]<p&&x<=n;x+=lowbit(x)) Val[x]^=v;
if (x>n) return;
int pos=find(x);
modify(rt[pos],1,n,x,v);
}
int Query(int x) {
if (ct[Lowbit(x)]<p) return Val[x];
int pos=find(x);
return query(rt[pos],1,n,1,x);
}
int main() {
freopen("fenwick.in","r",stdin);
freopen("fenwick.out","w",stdout);
n=read();q=read();k=read();
if (k==2) {
for(;q;q--) {
int opt=read(),x=read();
if (opt==1) modify(rt[0],1,n,x,read());
if (opt==2) write(query(rt[0],1,n,1,x));
}
return 0;
}
for(l=k;!(l&1);l>>=1) p++;
for(int x=n;x;x/=k) w++;
pw[0]=1;fo(i,1,w-1) pw[i]=pw[i-1]*k;
fo(i,1,w)
fo(j,0,k/2-1) {
int x=(2*j+1)*(1<<p);
if (x>=k||x*pw[i-1]>n) break;
Id[x*pw[i-1]]=++cnt;
for(int y=x;y<k;y*=2) g[y][0]=x;
}
fo(i,1,k) for(int x=i;!(x&1);x>>=1) ct[i]++;
fo(i,1,k) if (ct[i]>=p) inv[i*2%k]=i;
fo(j,1,30) fo(i,1,k) g[i][j]=g[inv[g[i][j-1]]][j-1];
for(;q;q--) {
int opt=read(),x=read();
if (opt==1) {
int v=read();
Modify(x,v);
}
if (opt==2) {
int ans=0;
for(;x;x-=lowbit(x)) ans^=Query(x);
write(ans);
}
}
return 0;
}