zoukankan      html  css  js  c++  java
  • string 线段树

    碰到题面就回忆起线段树专题的排序,然而模完样例发现思路无关。然后又想到splay里的文艺平衡树,然而那个是区间翻转。草草的敲了快排,发现自己可以码归并比比速度(自己sb一样,明明都是O(n*logn)),然后kx地拍了一整场考试,速度都差不多。正解是桶排+线段树优化。考虑桶排,在原专题中的排序一题中好多人都靠桶排水过了,但其实时间是6000ms,(hiahia)这题直接桶排暴力和sort一个分。所以考虑正解的思考过程,桶排排序很快,但预处理,加统计到序列中都是O(n)。但仔细斟酌可以发现这两个操作都是处理区间问题,一个查询,一个修改。但泛泛的说还不够,你会发现你不明确线段树存什么,想想桶排,桶数组是思路的源泉,而且只有26种元素,那么答案显而易见了,开26颗对应桶下标的线段树。修改是覆盖成1,查询同时再覆盖成0。思路很棒!

    #include<cstdio>
    #include<iostream>
    #define MAXN 100010
    #define TR (MAXN<<2)
    using namespace std;
    inline int read(){
    	int s=0;char ch=getchar();
    	while(ch<'0'||ch>'9')ch=getchar();
    	while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
    	return s;
    }
    #define kd (read())
    int n,m;
    int tong[27];
    int sm[27][TR],lb[27][TR];
    #define ls (u<<1)
    #define rs (u<<1|1)
    inline void up(int u,int id){
    	sm[id][u]=sm[id][ls]+sm[id][rs];
    }
    inline void down(int u,int l,int r,int id){
    	if(!lb[id][u])return ;
    	int mid=l+r>>1;
    	lb[id][ls]=lb[id][rs]=lb[id][u];
    	if(lb[id][u]==-1)
    		sm[id][rs]=sm[id][ls]=0;
    	else{
    		sm[id][ls]=mid-l+1;
    		sm[id][rs]=r-mid;
    	}
    	lb[id][u]=0;
    }
    void upd(int u,int l,int r,int x,int y,int id){
    	if(l>=x&&r<=y){
    		sm[id][u]=(r-l+1);
    		lb[id][u]=1;
    		return ;
    	}
    	down(u,l,r,id);
    	int mid=l+r>>1;
    	if(x<=mid)upd(ls,l,mid,x,y,id);
    	if(y>=mid+1)upd(rs,mid+1,r,x,y,id);
    	up(u,id);
    }
    int query(int u,int l,int r,int x,int y,int id){
    	if(!sm[id][u])return 0;
    	if(l>=x&&r<=y){
    		int res=sm[id][u];
    		sm[id][u]=0;
    		lb[id][u]=-1;
    		return res;
    	}
    	down(u,l,r,id);
    	int mid=l+r>>1;
    	int res=0;
    	if(x<=mid)res+=query(ls,l,mid,x,y,id);
    	if(y>=mid+1)res+=query(rs,mid+1,r,x,y,id);
    	up(u,id);
    	return res;
    }
    void wks(int l,int r){
    	for(int i=1;i<=26;++i)
    		tong[i]=query(1,1,n,l,r,i);
    	int p=l;
    	for(int i=1;i<=26;++i)
    		if(tong[i]){
    			upd(1,1,n,p,p+tong[i]-1,i);
    			p=p+tong[i];
    		}
    }
    void wkj(int l,int r){
    	for(int i=1;i<=26;++i)
    		tong[i]=query(1,1,n,l,r,i);
    	int p=l;
    	for(int i=26;i>=1;--i)
    		if(tong[i]){
    			upd(1,1,n,p,p+tong[i]-1,i);
    			p=p+tong[i];
    		}
    }
    void pt(int u,int l,int r){
    	if(l==r){
    		for(int i=1;i<=26;++i)
    			if(sm[i][u]){putchar(i+'a'-1);break;}
    		return ;
    	}
    	for(int i=1;i<=26;++i)
    		down(u,l,r,i);
    	int mid=l+r>>1;
    	pt(ls,l,mid);pt(rs,mid+1,r);
    }
    int main(){
    //	freopen("da.in","r",stdin);
    	n=kd;m=kd;
    	char rn;
    	for(int i=1;i<=n;++i){
    		rn=getchar();
    		upd(1,1,n,i,i,(rn-'a'+1));
    	}
    	int l,r,opt;
    	for(int i=1;i<=m;++i){
    		l=kd;r=kd;opt=kd;
    		switch(opt){
    			case 1:{wks(l,r);break;}
    			case 0:{wkj(l,r);break;}
    		}
    	}
    	pt(1,1,n);
    	puts("");
    }
    

     线段树习惯不好,down函数最好放在判断下面,此时才能保证节点数为MAXN×4

  • 相关阅读:
    UVA 408 (13.07.28)
    linux概念之用户,组及权限
    Java实现 蓝桥杯 历届试题 网络寻路
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 九宫重排
    Java实现 蓝桥杯 历届试题 九宫重排
  • 原文地址:https://www.cnblogs.com/2018hzoicyf/p/11285521.html
Copyright © 2011-2022 走看看