JZOJ P5829 HZOI 20190801 A string 线段树

题面:https://www.cnblogs.com/Juve/articles/11286476.html

考场上想起了排序这道题:https://www.cnblogs.com/Juve/p/11269638.html

n遍二分?

亲测TLE,0分

你暴力sort都有40分

当然这题不用这样

我们借鉴排序的思路

我们用线段树来完成操作,那么我们想线段树存什么,懒标记是什么

借鉴刚才那道题,我们将节点信息和懒标记合二为一

设tr[k].val,如果k管辖的区间里的字母都是同一个字母,则tr[k].val就是那个字母,否则tr[k].val=0,

这样十分方便维护:

down:

if(!tr[k].val) return ;
tr[k<<1].val=tr[k<<1|1].val=tr[k].val;

up:

if(tr[k<<1].val==tr[k<<1|1].val)
	tr[k].val=tr[k<<1].val;

我们每次对于一次排序[L,R],查询[L,R],中26个字母出现的次数cnt[i],

实现:

if(opl<=l&&r<=opr&&tr[k].val){
	cnt[tr[k].val]+=(r-l+1);
	return ;
}

如果升序,就把[L,R]中前cnt[a]修改成a,接下来cnt[b]修改成b,。。。。。。

降序就反过来

最后输出也是一遍线段树dfs,然后。。。其实没什么了

来代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define MAXN 100005
#define re register
using namespace std;
int n,m,a[MAXN],cnt[28];
char ch[MAXN]
struct Segtree{
	int l,r,val;
}tr[MAXN<<2];
void down(int k,int data){
	if(!tr[k].val) return ;
	tr[k<<1].val=tr[k<<1|1].val=tr[k].val;
	tr[k].val=data;
}
void build(int k,int l,int r){
	tr[k].l=l,tr[k].r=r;
	if(l==r){
		tr[k].val=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid),build(k<<1|1,mid+1,r);
	if(tr[k<<1].val==tr[k<<1|1].val)
		tr[k].val=tr[k<<1].val;
}
void get_cnt(int k,int opl,int opr){
	int l=tr[k].l,r=tr[k].r;
	if(opl<=l&&r<=opr&&tr[k].val){
		cnt[tr[k].val]+=(r-l+1);
		return ;
	}
	down(k,tr[k].val);
	int mid=(l+r)>>1;
	if(opl<=mid) get_cnt(k<<1,opl,opr);
	if(opr>mid) get_cnt(k<<1|1,opl,opr);
}
void change(int k,int opl,int opr,int data){
	if(tr[k].val==data) return ;
	int l=tr[k].l,r=tr[k].r;
	if(opl<=l&&r<=opr){
		tr[k].val=data;
		return ;
	}
	down(k,0);
	int mid=(l+r)>>1;
	if(opl<=mid) change(k<<1,opl,opr,data);
	if(opr>mid) change(k<<1|1,opl,opr,data);
	if(tr[k<<1].val==tr[k<<1|1].val)
		tr[k].val=tr[k<<1].val;
}
void print(int k){
	if(tr[k].val){
		int l=tr[k].l,r=tr[k].r;
		for(int i=l;i<=r;i++)
			putchar(tr[k].val-1+'a');
		return ;
	}
	print(k<<1),print(k<<1|1);
}
int main(){
	scanf("%d%d",&n,&m);
	scanf("%s",ch+1);
	for(re int i=1;i<=n;i++)
		a[i]=ch[i]-'a'+1;
	build(1,1,n);
	for(re int i=1,x,l,r;i<=m;i++){
		scanf("%d%d%d",&l,&r,&x);
		memset(cnt,0,sizeof(cnt));
		get_cnt(1,l,r);
		if(x==0){
			for(re int j=26;j>=1;j--){
				change(1,l,l+cnt[j]-1,j);
				l+=cnt[j];
			}
		}else{
			for(re int j=1;j<=26;j++){
				change(1,l,l+cnt[j]-1,j);
				l+=cnt[j];
			}
		}
	}
	print(1);
	puts("");
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/Juve/p/11286506.html
今日推荐