[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;
}

posted @ 2019-03-11 21:46  ylsoi  阅读(200)  评论(0编辑  收藏  举报