zoukankan      html  css  js  c++  java
  • UOJ#218. 【UNR #1】火车管理 线段树 主席树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ218.html

    题解

    如果我们可以知道每次弹出栈之后新的栈顶是什么,那么我们就可以在一棵区间覆盖、区间求和的线段树上完成这个问题。

    于是本题的重点转到了如何求新的栈顶。

    考虑用一个主席树维护一下每一个时刻每一个位置的栈顶元素的进栈时间,那么新的栈顶就是 当前位置栈顶的进栈时间-1 这时候的栈顶元素,然后这个东西也可以用我们维护的进栈时间来得到,所以我们只需要弄一个支持区间覆盖单点查询历史版本的主席树;这里区间覆盖有一个小技巧:假设节点 x 所代表的区间都被覆盖了,那么修改完 val[x] 之后令 ls[x] = rs[x] = x 即可。

    代码

    #include <bits/stdc++.h>
    #define clr(x) memset(x,0,sizeof (x))
    using namespace std;
    typedef long long LL;
    LL read(){
    	LL x=0,f=0;
    	char ch=getchar();
    	while (!isdigit(ch))
    		f|=ch=='-',ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	return f?-x:x;
    }
    const int N=500005;
    int n,m,k;
    int lastans=0;
    int hisv[N];
    namespace seg{
    	const int S=N<<2;
    	int sum[S],add[S],len[S];
    	void build(int rt,int L,int R){
    		len[rt]=R-L+1,sum[rt]=add[rt]=0;
    		if (L==R)
    			return;
    		int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    		build(ls,L,mid);
    		build(rs,mid+1,R);
    	}
    	void pushdown(int rt){
    		int ls=rt<<1,rs=ls|1;
    		if (add[rt]){
    			add[ls]=add[rs]=add[rt];
    			sum[ls]=add[rt]*len[ls];
    			sum[rs]=add[rt]*len[rs];
    			add[rt]=0;
    		}
    	}
    	void update(int rt,int L,int R,int xL,int xR,int v){
    		if (R<xL||L>xR)
    			return;
    		if (xL<=L&&R<=xR){
    			sum[rt]=v*len[rt];
    			add[rt]=v;
    			return;
    		}
    		pushdown(rt);
    		int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    		update(ls,L,mid,xL,xR,v);
    		update(rs,mid+1,R,xL,xR,v);
    		sum[rt]=sum[ls]+sum[rs];
    	}
    	int Query(int rt,int L,int R,int xL,int xR){
    		if (R<xL||L>xR)
    			return 0;
    		if (xL<=L&&R<=xR)
    			return sum[rt];
    		pushdown(rt);
    		int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    		return Query(ls,L,mid,xL,xR)+Query(rs,mid+1,R,xL,xR);
    	}
    }
    namespace pt{
    	const int S=N*100;
    	int val[S],ls[S],rs[S],root[N],cnt;
    	void init(){
    		root[0]=cnt=ls[1]=rs[1]=1;
    		val[1]=0;
    	}
    	void update(int prt,int &rt,int L,int R,int xL,int xR,int v){
    		if (R<xL||L>xR)
    			return;
    		if (rt==prt)
    			rt=++cnt,val[rt]=val[prt],ls[rt]=ls[prt],rs[rt]=rs[prt];
    		if (xL<=L&&R<=xR){
    			val[rt]=v;
    			ls[rt]=rs[rt]=rt;
    			return;
    		}
    		int mid=(L+R)>>1;
    		update(ls[prt],ls[rt],L,mid,xL,xR,v);
    		update(rs[prt],rs[rt],mid+1,R,xL,xR,v);
    	}
    	int Query(int rt,int L,int R,int x){
    		if (L==R)
    			return val[rt];
    		int mid=(L+R)>>1;
    		if (x<=mid)
    			return Query(ls[rt],L,mid,x);
    		else
    			return Query(rs[rt],mid+1,R,x);
    	}
    }
    using pt::root;
    int main(){
    	n=read(),m=read(),k=read();
    	seg::build(1,1,n);
    	pt::init();
    	hisv[0]=0;
    	for (int T=1;T<=m;T++){
    		root[T]=root[T-1];
    		int type=read(),L=(read()+lastans*k)%n+1,R,x;
    		if (type==1){
    			R=(read()+lastans*k)%n+1;
    			if (L>R)
    				swap(L,R);
    			printf("%d
    ",lastans=seg::Query(1,1,n,L,R));
    		}
    		else if (type==2){
    			int t1=pt::Query(root[T-1],1,n,L);
    			t1=pt::Query(root[max(t1-1,0)],1,n,L);
    			seg::update(1,1,n,L,L,hisv[t1]);
    			pt::update(root[T-1],root[T],1,n,L,L,t1);
    		}
    		else if (type==3){
    			R=(read()+lastans*k)%n+1,x=read();
    			if (L>R)
    				swap(L,R);
    			hisv[T]=x;
    			seg::update(1,1,n,L,R,x);
    			pt::update(root[T-1],root[T],1,n,L,R,T);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    获取SqlServer数据库、表(字段、索引..)、视图、存储过程等信息脚本
    C# 资源Resources.resx中文件的获取、读取及复制
    C# 解锁从互联网下载的需要右键属性“解除锁定”的文件
    SqlServer根据生日计算年龄,精确到年(岁)月日小时分秒
    PHP设计模式—模板方法模式
    YII2中beforeSave和TimestampBehavior的使用,自动更新创建时间,更新时间
    YII2中like查询单边匹配%
    开发中 利用 spring利用扩展点 applicationContextAware,BeanNameAware实现模板+策略模式
    Spring RestTemplate调用接口乱码解决
    设计模式学习
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ218.html
Copyright © 2011-2022 走看看