zoukankan      html  css  js  c++  java
  • Uoj #218. 【UNR #1】火车管理 可持久化线段树+思维

    前几周考试的时候考了,正解给的是线段树套堆(专门卡这个做法的空间). 
     
    这里先写一下可持久化线段树的做法(应该是官方正解吧). 
     
    搞两个线段树,一个维护的是权值(查询答案时调用的).

    另一个维护的是每个下标在每一个操作时刻被哪个操作在顶上覆盖着(这是一个可持久化线段树).

    这样做有什么好处呢 ?

    我们举个例子:
     
     假设这是一个 $l$ 位置的栈.

     当前要进行弹栈操作.

     在 $rt[i-1]$ 中查询,能查到 $o$ (最新一次压栈).

     我们知道,$o$ 压入的数是要被弹出去的,取而代之的是 $oo$ 所压入的数.
     
     我们在 $rt[o-1]$ 中再查询一次就可以查到 $oo$ 了.

     对应的,只需在第一颗维护权值的线段树中把对应点赋值为 $oo$ 所对应的权值即可.

     在可持久化线段树中的操作是新建一个 $i$ 版本,与 $i-1$ 唯一不同就是 $o->oo$.

     区间压栈在两颗线段树中对应的都是区间赋值. 
    #include<bits/stdc++.h>
    #define maxn 500005   
    using namespace std;
    int n,Q,ty,lastans=0; 
    int rt[maxn], tim[maxn], lp[maxn], tp[maxn];     
    void setIO(string s)
    {
    	string in=s+".in"; 
    	string out=s+".out"; 
    	freopen(in.c_str(),"r",stdin); 
    	freopen(out.c_str(),"w",stdout);     
    }
    namespace tree1
    {
    	#define lson ( x<<1)
    	#define rson ( (x<<1)|1)      
    	int sumv[500005<<2],lazy[500005<<2];        
    	void mark(int l,int r,int x,int k)
    	{
    		sumv[x]=(r-l+1)*k; 
    		lazy[x]=k; 
    	}
    	void pushup(int x)
    	{
    		sumv[x]=sumv[lson]+sumv[rson]; 
    	}
    	void pushdown(int l,int r,int x)
    	{
    		if(!lazy[x]) return; 
    		int mid=(l+r)>>1; 
    		if(mid >= l) mark(l, mid, lson, lazy[x]); 
    		if(r > mid) mark(mid + 1, r, rson, lazy[x]);     
    		lazy[x]=0;     
    	}
    	void update(int l,int r,int x,int L,int R,int k)
    	{
    		if(l>=L&&r<=R)      
    		{
    			mark(l,r,x,k); 
    			return; 
    		}
    		pushdown(l,r,x); 
    		int mid=(l+r)>>1; 
    		if(L<=mid) update(l,mid,lson,L,R,k); 
    		if(R>mid) update(mid+1,r,rson,L,R,k); 
    		pushup(x); 
    	} 
    	int query(int l,int r,int x,int L,int R)
    	{
    		if(l>=L&&r<=R) return sumv[x]; 
    		pushdown(l, r, x); 
    		int mid=(l+r)>>1, tmp=0; 
    		if(L<=mid) tmp+=query(l,mid,lson,L,R); 
    		if(R>mid) tmp+=query(mid+1,r,rson,L,R); 
    		return tmp; 
    	}
    	#undef lson
    	#undef rson 
    }; 
    
    
    namespace tree2
    {
    	int tot=0; 
    	int tag[maxn*75],value[maxn*75];          
    	int lson[maxn*75],rson[maxn*75];  
    	void mark(int x,int delta)
    	{
    		value[x]=tag[x]=delta; 
    		return; 
    	}
    	void pushdown(int l,int r,int x)
    	{
    		if(!tag[x]) return; 
    		int mid=(l+r)>>1;         
    		if(mid>=l && !lson[x]) lson[x]=++tot; 
    		if(r > mid && !rson[x]) rson[x]=++tot;       
    		if(lson[x]) mark(lson[x], tag[x]); 
    		if(rson[x]) mark(rson[x], tag[x]); 
    		tag[x]=0;  
    	}        
    	void add(int &k,int kk,int l,int r,int L,int R,int delta)
    	{
    		tag[k=++tot]=0;
    		if(l>=L&&r<=R)       
    		{
    			mark(k, delta); 
    			return; 
    		}
    		int mid=(l+r)>>1; 
    		pushdown(l,r,kk); 
    		lson[k]=lson[kk], rson[k]=rson[kk];            
    		if(L <= mid) add(lson[k], lson[kk], l, mid, L, R, delta); 
    		if(R > mid) add(rson[k], rson[kk], mid + 1, r, L, R, delta);      
    	}
    	int query(int l,int r,int k,int pos)
    	{
    		if(!k || l == r) return value[k]; 
    		pushdown(l,r,k); 
    		int mid=(l+r)>>1;
    		if(pos<=mid) 
    			return query(l,mid,lson[k], pos); 
    		else 
    			return query(mid+1,r,rson[k],pos); 
    	}
    }; 
    int main()
    {    
    	// setIO("input"); 
    	scanf("%d%d%d",&n,&Q,&ty); 
    	int opt,l,r,dd; 	
    	for(int i=1;i<=Q;++i) 
    	{
    		scanf("%d",&opt);    
    		switch(opt)
    		{
    			case 1 : 
    			{
    				scanf("%d%d",&l,&r);    
    				l=(l+lastans*ty)%n+1; 
    				r=(r+lastans*ty)%n+1; 
    				if(l>r) swap(l,r); 
    				lastans=tree1::query(1,n,1,l,r);              
    				printf("%d
    ",lastans); 
    				rt[i]=rt[i-1];          
    				break; 
    			}
    			case 2 : 
    			{ 
    				scanf("%d",&l);     
    				l=(l+lastans*ty)%n+1;  
    				int o = tree2::query(1, n, rt[i-1],l);               //查询修改的 l 的修改操作.     
    				if(!o) rt[i]=rt[i-1];                   
    				else 
    				{         
    					int oo = tree2::query(1,n,rt[o-1],l);            // 上一次操作   
    					tree1::update(1,n,1,l,l,tp[oo]);      //            
    					tree2::add(rt[i], rt[i-1], 1, n, l,l,oo);         
    				}
    				break; 
    			}
    			case 3 : 
    			{
    				scanf("%d%d%d",&l,&r,&dd); 
    				l=(l+lastans*ty)%n+1; 
    				r=(r+lastans*ty)%n+1; 
    				if(l>r) swap(l,r);  
    				tp[i]=dd; 
    				tree1::update(1,n,1,l,r,dd);      
    				tree2::add(rt[i],rt[i-1],1,n,l,r,i);                
    				break; 
    			}
    		}
    	}
    	return 0; 
    }
    

      

  • 相关阅读:
    Android Studio插件
    android漂亮的对话框项目sweet-alert-dialog
    Android中Context详解 ---- 你所不知道的Context
    Bundle对象的使用
    Android利用Http下载文件
    文件缓存(配合JSON数组)
    android studio sqlite操作代码片段
    Android中使用ListView实现分页刷新(线程休眠模拟)(滑动加载列表)
    Android Studio 配置使用百度api (附带简单样例)
    9套Android实战经典项目资料分享给大家
  • 原文地址:https://www.cnblogs.com/guangheli/p/11022707.html
Copyright © 2011-2022 走看看