[uoj218]火车管理——主席树
题目大意
维护一个栈,每次区间压栈,单点弹栈,区间询问栈顶的元素和。
思路
如果没有弹栈的操作的话,我们每一次只需要在一颗线段树上面区间赋值即可。
加上弹栈操作,我们每次就需要知道当前栈顶元素的上一个元素是什么,考虑用主席树来维护每一个时刻每一个位置的最近一次的修改位置。
假设当前的时间为x且我们需要弹栈,那么我们需要先查询得到最近的一次时间y,然后查询y-1的修改时间z,那么我们就得到了栈顶下面的元素的修改时间。
然后我们需要将x点的这个元素的时间改为z,然后更新查询线段树上的答案即可。
不难发现我们实际上是向前维护了一个最近修改时间的链表,由于主席树的继承性质,直接查询y-1使得我们的答案是正确的。
/*=======================================
* Author : ylsoi
* Time : 2019.3.10
* Problem : uoj218
* E-mail : ylsoi@foxmail.com
* ====================================*/
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second
#define mk make_pair
#define pb push_back
#define mid ((l+r)>>1)
typedef long long ll;
using namespace std;
void File(){
freopen("uoj218.in","r",stdin);
freopen("uoj218.out","w",stdout);
}
template<typename T>void read(T &_){
_=0; T f=1; char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
_*=f;
}
string proc(){
ifstream f("/proc/self/status");
return string(istreambuf_iterator<char>(f),istreambuf_iterator<char>());
}
const int maxn=5e5+10;
int n,m,ty,ans,root[maxn],tot,w[maxn];
struct Segment_Tree{
#define lc o<<1
#define rc o<<1|1
#define lson lc,l,mid
#define rson rc,mid+1,r
int val[maxn<<2],sum[maxn<<2],las[maxn<<2];
void pushdown(int o,int l,int r){
if(las[o])las[lc]=las[rc]=las[o],las[o]=0;
if(val[o]){
val[lc]=val[rc]=val[o];
sum[lc]=(mid-l+1)*val[o];
sum[rc]=(r-mid)*val[o];
val[o]=0;
}
}
void update(int o,int l,int r,int L,int R,int x,int y){
if(L<=l && r<=R)val[o]=x,sum[o]=(r-l+1)*x,las[o]=y;
else{
pushdown(o,l,r);
if(L<=mid)update(lson,L,R,x,y);
if(R>=mid+1)update(rson,L,R,x,y);
sum[o]=sum[lc]+sum[rc];
}
}
int query_sum(int o,int l,int r,int L,int R){
if(L<=l && r<=R)return sum[o];
else{
pushdown(o,l,r);
int ret=0;
if(L<=mid)ret+=query_sum(lson,L,R);
if(R>=mid+1)ret+=query_sum(rson,L,R);
return ret;
}
}
int query_las(int o,int l,int r,int p){
if(l==r)return las[o];
pushdown(o,l,r);
if(p<=mid)return query_las(lson,p);
else return query_las(rson,p);
}
#undef lc
#undef rc
}T1;
struct Chairman_Tree{
int cnt;
struct node{int val,lc,rc;}t[maxn*120];
void insert(int &o,int l,int r,int L,int R,int x){
int now=++cnt;
t[now]=t[o],o=now,t[o].val=x;
if(L<=l && r<=R)t[o].lc=t[o].rc=(l==r ? 0 : o);
else{
if(L<=mid)insert(t[o].lc,l,mid,L,R,x);
if(R>=mid+1)insert(t[o].rc,mid+1,r,L,R,x);
}
}
int query(int o,int l,int r,int p){
if(l==r)return t[o].val;
if(p<=mid)return query(t[o].lc,l,mid,p);
else return query(t[o].rc,mid+1,r,p);
}
}T2;
int main(){
//File();
read(n),read(m),read(ty);
int op,l,r,x;
/*T1.update(1,1,n,1,2,1,1);
cout<<T1.query_sum(1,1,n,4,5)<<endl;
REP(i,1,n)printf("%d ",T1.query_sum(1,1,n,i,i));
printf("\n");*/
REP(i,1,m){
read(op);
if(op==1){
read(l),read(r);
l=(l+ans*ty)%n+1;
r=(r+ans*ty)%n+1;
if(l>r)swap(l,r);
printf("%d\n",ans=T1.query_sum(1,1,n,l,r));
}
else if(op==2){
read(l);
l=(l+ans*ty)%n+1;
int tim=T1.query_las(1,1,n,l);
if(tim){
int las=T2.query(root[tim-1],1,n,l);
++tot;
root[tot]=root[tot-1];
T2.insert(root[tot],1,n,l,l,las);
T1.update(1,1,n,l,l,w[las],las);
}
}
else{
read(l),read(r),read(x);
l=(l+ans*ty)%n+1;
r=(r+ans*ty)%n+1;
if(l>r)swap(l,r);
w[++tot]=x;
root[tot]=root[tot-1];
T2.insert(root[tot],1,n,l,r,tot);
T1.update(1,1,n,l,r,x,tot);
}
/*REP(j,1,n)printf("%d ",T1.query_sum(1,1,n,j,j));
printf("\n");*/
}
//cerr<<proc()<<endl;
return 0;
}