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

  • 相关阅读:
    没有一个计时器控制在VB6计时器功能
    检测系统范围内的鼠标事件
    c# Com
    tcpdump
    dd
    dumpe/dumpe2fs/e2fsck
    fdisk
    mkswap/swapon/swapoff/free
    mkfs/mk2fs/fsck/e2fsck/tune2fs/blkid
    parted
  • 原文地址:https://www.cnblogs.com/2018hzoicyf/p/11285521.html
Copyright © 2011-2022 走看看