思维题 + 板子题
这道题目蛮有趣的,但坑有点多,在下面会陈述。
题意
不做赘述。
注意出题人十分恶心地没给 (x),(y),(n) 的关系,请各位注意这点。
思路
看似很难维护,区间操作,但是我们可以利用 ( exttt{trie}) 的特性来造一棵不同寻常的线段树。
对于序列上的数的位置 (i) ,模 (2^x) 后,留下 (x) 位后缀,对比所有 (i) 模(2^{x-1}) 后留下的后缀,只是增加了第 (x) 位( (0) 或 (1) )。
因此我们可以把序列按这样构造一棵线段树,每个节点由父亲节点延伸出来,两个子节点的后缀相同,唯一区别最高位是 (0) 或 (1)。
???这不就是 ( exttt{trie}) 吗 ???
所以,这道题目的本意就是让你建一棵支持区间修改和查询的 ( exttt{trie}) ,按照线段树1的板子做就好了。
问题解决。
然后我WA了30+发
一定要注意三点:
-
记得先将 (y) 对 (x) 取模再做
-
(y mod 2^x > n) 此时不做修改,并且询问返回0
-
(y le n) 并且 (2^x > n) 此时返回 (a_y)
代码
还有一些细节在代码中
#include <bits/stdc++.h>
using namespace std;
#define ls n << 1
#define rs n << 1 | 1
#define int long long
const int N = 5e7;
inline int read()
{
register int s = 0;
register bool neg = 0;
register char c = getchar();
for (; c < '0' || c > '9'; c = getchar())
neg |= (c == '-');
for (; c >= '0' && c <= '9'; s = s * 10 + (c ^ 48), c = getchar())
;
return (neg ? -s : s);
}
int a,b,s[N+10],sum[N+10],lazy[N+10],t[N+10];
inline void up(int n) {
sum[n]=sum[ls]+sum[rs];
t[n]=t[ls]+t[rs];//区间长度
}
inline void down(int n) {
if(!lazy[n]) return;
if(t[ls]) sum[ls]+=t[ls]*lazy[n];//注意要判断儿子节点是否存在
if(t[rs]) sum[rs]+=t[rs]*lazy[n];
if(t[ls]) lazy[ls]+=lazy[n];
if(t[rs]) lazy[rs]+=lazy[n];
lazy[n]=0;
}
inline void insert(int n,int k,int p,int q) {
if(!q) {
t[n]=1;
sum[n]+=p;
return;
}
if(k&1ll) insert(rs,k>>1ll,p,q-1);
else insert(ls,k>>1ll,p,q-1);
up(n);
}
inline void change(int n,int k,int p,int q) {
if(!q) {//注意这里,return的关键是q为0,而不是k为0,因为前导0是有意义的
sum[n]+=p*t[n];
lazy[n]+=p;
return;
}
down(n);
if(k&1ll) change(rs,k>>1ll,p,q-1);
else change(ls,k>>1ll,p,q-1);
up(n);
}
inline int query(int n,int k,int q) {
if(!q) return sum[n];
down(n);
if(k&1ll) return query(rs,k>>1ll,q-1);
else return query(ls,k>>1ll,q-1);
}
signed main()
{
// freopen("in1.in", "r", stdin);
a=read();
b=read();
int mx=ceil(log2(a));
for(int i=1;i<=a;i++) s[i]=read(),insert(1,i,s[i],mx);
int x,y,z,lst=0,opt,cnt=0;
for(int i=1;i<=b;i++) {
opt=(read()+lst)%2+1;
if(opt==1) {
x=read();
y=read();
z=read();
y%=(1ll<<x);
if(x<=mx) change(1,y,z,x);
else if(y<=a) change(1,y,z,mx);
}
else {
x=read();
y=read();
y%=(1ll<<x);
if(x<=mx) printf("%lld
",lst=query(1,y,x));
else if(y<=a) printf("%lld
",lst=query(1,y,mx));
else printf("%lld
",lst=0);
}
}
return 0;
}