牛客練習賽29E 位運算?位運算! splay
阿新 • • 發佈:2018-12-16
Description
請實現一個數據結構支援以下操作: 區間迴圈左右移,區間與,區間或,區間求和。
所有操作形如 opt l r v。 opt=1 表示將區間[l,r]迴圈右移v位。 opt=2 表示將區間[l,r]迴圈左移v位。 opt=3 表示將區間[l,r]按位或上v。 opt=4 表示將區間[l,r]按位與上v。 opt=5 詢問區間[l,r]的和。 保證opt=1或2時 1 ≤ v ≤ 20 注意:為了優化你的做題體驗,操作5也會輸入一個v,但是是沒有意義的。 注意:迴圈左右移在20個二進位制位的意義下進行
1 ≤ N,Q ≤ 2*105 0 ≤ ai < 220 一些說明:
- 對於00000000000000000101,右移一位後會變成10000000000000000010
- 不是區間位移,是區間中的每一個數的二進位制位的位移
Solution
心態崩了,splay的做法常數昇天,調不出來打出gg
考慮套路做法。我們把二進位制的每一位單獨處理,區間&和|就按位討論,區間求和就是統計每一位上1的數量*這一位貢獻的和,區間左右移就是依次交換這些區間
注意到1、2操作的特殊性,我們可以 (不可以) 用splay維護20個區間,每次交換就切出來貼在目標位置上。這樣做理論上是nlog^2n的
然鵝,然鵝我的程式碼常數巨大,2e5的資料要跑15s。人生幾何,不如寫一些不那麼噁心的題目。。
Code
#include <stdio.h>
#include <string.h>
#include <bitset>
#define rep(i,st,ed) for (register int i=st,_=ed;i<=_;++i)
#define drp(i,st,ed) for (register int i=st,_=ed;i>=_;--i)
typedef long long LL;
const int N=200005;
struct treeNode {
int son[2],fa,size,tag,sum,val;
} t[N*22];
int a[N],root[21],last[21];
int w[N],wjp;
LL bin[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void push_up(int x) {
if (!x) return ;
t[x].size=t[t[x].son[0]].size+t[t[x].son[1]].size+1;
t[x].sum=t[x].val+t[t[x].son[0]].sum+t[t[x].son[1]].sum;
}
void push_down(int x) {
if (t[x].tag==-1) return ;
int w=t[x].tag; t[x].tag=-1;
if (t[x].son[0]) {
t[t[x].son[0]].tag=t[t[x].son[0]].val=w;
t[t[x].son[0]].sum=t[t[x].son[0]].size*w;
}
if (t[x].son[1]) {
t[t[x].son[1]].tag=t[t[x].son[1]].val=w;
t[t[x].son[1]].sum=t[t[x].son[1]].size*w;
}
}
void rotate(int x) {
int y=t[x].fa; int z=t[y].fa;
int k=t[y].son[1]==x;
t[z].son[t[z].son[1]==y]=x; t[x].fa=z;
t[y].son[k]=t[x].son[!k]; t[t[x].son[!k]].fa=y;
t[x].son[!k]=y; t[y].fa=x;
push_up(y); push_up(x);
}
void splay(int &root,int x,int goal=0) {
for (;t[x].fa!=goal;) {
int y=t[x].fa; int z=t[y].fa;
if (z!=goal) {
if ((t[y].son[1]==x)^(t[z].son[1]==y)) rotate(x);
else rotate(y);
}
rotate(x);
}
if (!goal) root=x;
}
int kth(int root,int k) {
int x=root;
for (;233;) {
push_down(x);
if (t[t[x].son[0]].size+1==k) return x;
if (t[t[x].son[0]].size>=k) x=t[x].son[0];
else {
k-=t[t[x].son[0]].size+1;
x=t[x].son[1];
}
}
}
int cut(int &root,int l,int r) {
int L=kth(root,l-1);
int R=kth(root,r+1);
splay(root,L); splay(root,R,root);
int ret=t[R].son[0];
t[ret].fa=t[R].son[0]=0;
push_up(R); push_up(L);
return ret;
}
int build(int l,int r) {
int mid=(l+r)>>1;
int pos=mid+wjp;
t[pos].tag=-1;
t[pos].size=1;
t[pos].val=w[mid-1];
if (l<mid) {
t[pos].son[0]=build(l,mid-1);
t[t[pos].son[0]].fa=pos;
}
if (mid<r) {
t[pos].son[1]=build(mid+1,r);
t[t[pos].son[1]].fa=pos;
}
push_up(pos);
return pos;
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
int n=read(),q=read();
rep(i,1,n) a[i]=read();
bin[0]=1; rep(i,1,19) bin[i]=bin[i-1]*2;
rep(j,0,19) {
rep(i,1,n) w[i]=(a[i]&bin[j])!=0;
root[j]=build(1,n+2);
wjp+=n+2;
}
for (;q--;) {
int opt=read(),l=read(),r=read(),v=read();
if (opt==2) {
rep(i,0,v-1) last[i]=cut(root[i],l+1,r+1);
rep(i,v,19) {
int rt=root[i];
int now=cut(rt,l+1,r+1);
t[t[rt].son[1]].son[0]=last[i-v];
t[last[i-v]].fa=t[rt].son[1];
push_up(t[rt].son[1]); push_up(rt);
last[i]=now; root[i]=rt;
}
rep(i,0,v-1) {
int rt=root[i];
t[t[rt].son[1]].son[0]=last[i+20-v];
t[last[i+20-v]].fa=t[rt].son[1];
push_up(t[rt].son[1]); push_up(rt);
root[i]=rt;
}
} else if (opt==1) {
drp(i,19,20-v) last[i]=cut(root[i],l+1,r+1);
drp(i,19-v,0) {
int rt=root[i];
int now=cut(rt,l+1,r+1);
int rs=t[rt].son[1];
t[t[rt].son[1]].son[0]=last[i+v];
t[last[i+v]].fa=t[rt].son[1];
push_up(t[rt].son[1]); push_up(rt);
last[i]=now; root[i]=rt;
}
drp(i,19,20-v) {
int rt=root[i]; int rs=t[rt].son[1];
t[rs].son[0]=last[i-20+v];
t[last[i-20+v]].fa=rs;
push_up(rs); push_up(rt);
root[i]=rt;
}
} else if (opt==3) {
rep(i,0,19) if (v&bin[i]) {
int rt=root[i];
splay(rt,kth(rt,l));
splay(rt,kth(rt,r+2),rt);
int tmp=t[t[rt].son[1]].son[0];
t[tmp].tag=t[tmp].val=1;
t[tmp].sum=t[tmp].size;
push_up(t[rt].son[1]); push_up(rt);
root[i]=rt;
}
} else if (opt==4) {
rep(i,0,19) if (!(v&bin[i])) {
int rt=root[i];
splay(rt,kth(rt,l));
splay(rt,kth(rt,r+2),rt);
int rs=t[rt].son[1];
int tmp=t[rs].son[0];
t[tmp].tag=t[tmp].val=t[tmp].sum=0;
push_up(rs); push_up(rt);
root[i]=rt;
}
} else {
LL ans=0;
rep(i,0,19) {
int rt=root[i];
splay(rt,kth(rt,l));
splay(rt,kth(rt,r+2),rt);
ans+=bin[i]*t[t[t[rt].son[1]].son[0]].sum;
root[i]=rt;
}
printf("%lld\n", ans);
}
}
return 0;
}