题意
有n个栈,现在要资瓷以下操作:
1 l r询问编号在[l,r]之间的栈的栈顶的和
2 l对编号为l的栈进行一次pop操作
3 l r x对编号在[l,r]之间的栈进行一次push(x)操作
分析
这题的extra test卡空间真的是丧心病狂,在卡空间的时候还出现了同一个程序有时可以跑有时会re的神奇情况,简直不能再爽。
这题的话,用一棵线段树来维护答案和每个位置当前的栈顶是什么时候push进来的,再用一棵可持久化线段树来维护每个操作后每个点往前第一个覆盖到它的操作是哪个。
询问就直接在答案线段树上询问,修改操作就分别在两棵线段树上改一下,就做完了。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
const int N=500005;
int n,m,ty,sz,rt[N],root,w[N],tot,u,v,z;
struct tree{int l,r,s,tag;}t[N*140];
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void pushdown(int d,int l,int r)
{
if (l==r||!t[d].tag) return;
int x=t[d].tag,mid=(l+r)/2;t[d].tag=0;
if (!t[d].l) t[d].l=++sz;
if (!t[d].r) t[d].r=++sz;
t[t[d].l].tag=t[t[d].r].tag=x;
t[t[d].l].s=w[x]*(mid-l+1);
t[t[d].r].s=w[x]*(r-mid);
}
int query(int d,int l,int r,int x,int y)
{
if (!d) return 0;
pushdown(d,l,r);
if (x<=l&&r<=y) return t[d].s;
int mid=(l+r)/2;
if (y<=mid) return query(t[d].l,l,mid,x,y);
else if (x>mid) return query(t[d].r,mid+1,r,x,y);
else return query(t[d].l,l,mid,x,y)+query(t[d].r,mid+1,r,x,y);
}
int get_id2(int d,int l,int r,int x)
{
pushdown(d,l,r);
if (l==r) return t[d].tag;
int mid=(l+r)/2;
if (x<=mid) return get_id2(t[d].l,l,mid,x);
else return get_id2(t[d].r,mid+1,r,x);
}
void modify(int &d,int l,int r)
{
if (!d) d=++sz;
pushdown(d,l,r);
if (u<=l&&r<=v) {t[d].tag=z;t[d].s=(r-l+1)*w[z];return;}
int mid=(l+r)/2;
if (u<=mid) modify(t[d].l,l,mid);
if (v>mid) modify(t[d].r,mid+1,r);
t[d].s=t[t[d].l].s+t[t[d].r].s;
}
void pushdown(int d)
{
if (!t[d].tag) return;
int x=t[d].tag,tmp;t[d].tag=0;
tmp=t[d].l;t[d].l=++sz;t[t[d].l]=t[tmp];
tmp=t[d].r;t[d].r=++sz;t[t[d].r]=t[tmp];
t[t[d].l].tag=t[t[d].r].tag=x;
}
int get_id1(int d,int l,int r,int x)
{
if (t[d].tag) return t[d].tag;
if (l==r) return t[d].tag;
int mid=(l+r)/2;
if (x<=mid) return get_id1(t[d].l,l,mid,x);
else return get_id1(t[d].r,mid+1,r,x);
}
void ins(int &d,int l,int r,bool flag)
{
if (flag) {int p=d;d=++sz;t[d]=t[p];}
flag=1;
if (l<r&&t[d].tag) pushdown(d),flag=0;
if (u<=l&&r<=v) {t[d].tag=z;return;}
int mid=(l+r)/2;
if (u<=mid) ins(t[d].l,l,mid,flag);
if (v>mid) ins(t[d].r,mid+1,r,flag);
}
int main()
{
n=read();m=read();ty=read();
int ans=0;
while (m--)
{
int op=read();
if (op==1)
{
int l=(read()+ans*ty)%n+1,r=(read()+ans*ty)%n+1;
if (l>r) std::swap(l,r);
printf("%d\n",ans=query(root,1,n,l,r));
}
else if (op==2)
{
int l=(read()+ans*ty)%n+1,id=get_id2(root,1,n,l);
id=get_id1(rt[id-1],1,n,l);
u=l;v=l;z=id;
modify(root,1,n);
tot++;rt[tot]=rt[tot-1];
ins(rt[tot],1,n,1);
}
else
{
int l=(read()+ans*ty)%n+1,r=(read()+ans*ty)%n+1,x=read();
if (l>r) std::swap(l,r);
tot++;w[tot]=x;rt[tot]=rt[tot-1];
u=l;v=r;z=tot;
ins(rt[tot],1,n,1);
modify(root,1,n);
}
}
return 0;
}