• 你这衣服租来的吗


    一道简单的数据结构题。
    题目要区间赋值,所以使用颜色段均摊。
    使用一个set维护相同颜色的连续区间。
    维护若干个线段树,线段树的下标(i)表示:如果线段树上当前位置的颜色等于线段树对应的颜色,则该下标处的值为1,否则为0。
    更新这些线段树可以使用区间加法。
    在set更新区间的时候顺便在线段树上加法。
    查询时可以在对应颜色的线段树上二分。
    时间复杂度(O((n+q)log_2n))

    #include<bits/stdc++.h>
    using namespace std;
    #define N 500010
    int n,m,rt[N],a[N],lc[N*30],rc[N*30],s[N*30],tg[N*30],ct,sl[N],tp,tl[N],tr[N],cc;
    void pd(int o,int l,int r){
    	if(tg[o]){
    		int md=(l+r)/2;
    		if(!lc[o])
    			lc[o]=++ct;
    		if(!rc[o])
    			rc[o]=++ct;
    		s[lc[o]]+=(md-l+1)*tg[o];
    		s[rc[o]]+=(r-md)*tg[o];
    		tg[lc[o]]+=tg[o];
    		tg[rc[o]]+=tg[o];
    		tg[o]=0;
    	}
    }
    struct no{
    	int l,r,z;
    };
    int operator <(no x,no y){
    	return x.r<y.r;
    }
    set<no>st;
    set<no>::iterator it,ii,iv;
    map<int,int>ma;
    void sp(int x){
    	it=st.lower_bound((no){0,x});
    	no p=*it;
    	if(p.l!=x){
    		st.erase(it);
    		st.insert((no){p.l,x-1,p.z});
    		st.insert((no){x,p.r,p.z});
    	}
    }
    void ad(int &o,int l,int r,int x,int y,int z){
    	if(!o)
    		o=++ct;
    	if(r<x||y<l)
    		return;
    	if(x<=l&&r<=y){
    		tg[o]+=z;
    		s[o]+=z*(r-l+1);
    		return;
    	}
    	pd(o,l,r);
    	int md=(l+r)/2;
    	ad(lc[o],l,md,x,y,z);
    	ad(rc[o],md+1,r,x,y,z);
    	s[o]=s[lc[o]]+s[rc[o]];
    }
    int k;
    int ef(int o,int l,int r,int k){
    	if(l==r)
    		return l;
    	int md=(l+r)/2;
    	pd(o,l,r);
    	if(s[lc[o]]>=k)
    		return ef(lc[o],l,md,k);
    	k-=s[lc[o]];
    	return ef(rc[o],md+1,r,k);
    }
    void qp(int o,int l,int r,int x,int y){
    	if(!o)
    		return;
    	if(r<x||y<l)
    		return;
    	if(x<=l&&r<=y){
    		sl[++tp]=o;
    		tl[tp]=l;
    		tr[tp]=r;
    		return;
    	}
    	int md=(l+r)/2;
    	pd(o,l,r);
    	qp(lc[o],l,md,x,y);
    	qp(rc[o],md+1,r,x,y);
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		if(!ma.count(a[i])){
    			ma[a[i]]=++cc;
    			a[i]=cc;
    		}
    		else
    			a[i]=ma[a[i]];
    		st.insert((no){i,i,a[i]});
    		ad(rt[a[i]],1,n,i,i,1);
    	}
    	int la=0;
    	for(int i=1;i<=m;i++){
    		char c[5];
    		scanf("%s",c);
    		if(c[0]=='M'){
    			int l,r,z;
    			scanf("%d%d%d",&l,&r,&z);
    			l^=la;
    			r^=la;
    			z^=la;
    			if(!ma.count(z)){
    				ma[z]=++cc;
    				z=cc;
    			}
    			else
    				z=ma[z];
    			sp(l);
    			if(r+1<=n)
    				sp(r+1);
    			it=st.lower_bound((no){0,l});
    			ii=st.lower_bound((no){0,r+1});
    			for(;it!=ii;it++){
    				no x=*it;
    				ad(rt[x.z],1,n,x.l,x.r,-1);
    				ad(rt[z],1,n,x.l,x.r,1);
    			}
    			it=st.lower_bound((no){0,l});
    			for(;it!=ii;){
    				iv=it;
    				it++;
    				st.erase(iv);
    			}
    			st.insert((no){l,r,z});
    		}
    		else{
    			int l,r,v;
    			scanf("%d%d%d%d",&l,&r,&k,&v);
    			l^=la;
    			r^=la;
    			k^=la;
    			v^=la;
    			if(!ma.count(v)){
    				ma[v]=++cc;
    				v=cc;
    			}
    			else
    				v=ma[v];
    			tp=0;
    			qp(rt[v],1,n,l,r);
    			int ok=0;
    			for(int i=1;i<=tp;i++){
    				if(s[sl[i]]<k)
    					k-=s[sl[i]];
    				else{
    					la=ef(sl[i],tl[i],tr[i],k);
    					ok=1;
    					printf("%d
    ",la);
    					break;
    				}
    			}
    			if(!ok){
    				la=0;
    				puts("0");
    			}
    		}
    	}
    	puts("");
    }
    
  • 相关阅读:
    反射
    jQuery之Dom操作
    Jquery学习开篇
    c#构造函数
    c#之委托
    DataX启动步骤解析
    JobContainer
    DataX 启动配置
    DataX源码分析(2)
    DataX源码分析(1)
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/14142411.html
Copyright © 2020-2023  润新知