Loading

string

这道题是我的耻辱,一开考看到\(40pts\)及其好拿,一想肯定所有人都拿了(伏笔),然后就想想正解。

一开始想了个转化成增减性线段树维护,后来发现无法映射到原序列上
后来又想维护差分和前缀和序列,无果
又想局部排序是不是归并,想扩展一下归并树,无果。
然后自己摸了一个样例,想维护前缀中有几个小于等于他的。
然后想到了实现方法,就开始码。
码完树状数组,权值线段树,线段树后,发现有一个操作不对。
然后真的不对了,就想怎么弥补,然后考试结束了。
整场考试无提交。

code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long
#define R register int
#define printf Ruusupuu = printf

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef unsigned long long G ;
const int N = 1e5 + 10 ;

int Ruusupuu ;

inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch ^ '0' ) , ch = getchar() ;
	return fg ? -w : w ;
}

int n , m , k [N] , a [N] , gnt , tnt , rt , l [30] , st [N] , top ;
char ch ;
struct W{ int cnt , l , r , ls , rs ; } g [N << 5] ;
struct T{ int data , l , r , lz ; } t [N << 5] ;

inline int lb( int x ){ return x & -x ; }
inline void add( int x ){ for( ; x <= 26 ; x += lb( x ) ) l [x] ++ ; }
inline int ask( int x ){ int ans = 0 ; for( ; x ; x -= lb( x ) ) ans += l [x] ; return ans ; }
inline void udd( int x ){ g [x].cnt = g [g [x].ls].cnt + g [g [x].rs].cnt ; }
inline void ud( int x ){ t [x].data = min( t [x << 1].data , t [x << 1 | 1].data ) ; }

inline void sp( int x ){


}

inline void ins( int &x , int l , int r , int pos , int w ){
//	printf( "%ld %ld\n" , l , r ) ;
	if( !x ) x = ++ gnt , g [x].l = l , g [x].r = r ;
	
	if( l == r ) { g [x].cnt += w ; return ; }
	int mid = ( l + r ) >> 1 ;
	if( pos <= mid ) ins( g [x].ls , l , mid , pos , w ) ;
	else ins( g [x].rs , mid + 1 , r , pos , w ) ;
	udd( x ) ;  
}

inline int sr( int x , int w ){
//	printf( "%ld %ld %ld\n" , g [x].l , g [x].r , w ) ;
	if( g [x].l == g [x].r ) { g [x].cnt -- ; return g [x].l ; }
	int mid = g [g [x].ls].cnt ;
	if( w <= mid ) { int ans = sr( g [x].ls , w ) ; udd ( x ) ; return ans ; }
	else { int ans = sr( g [x].rs , w - mid ) ; udd ( x ) ; return ans ; }  
}

inline void build( int x , int l , int r ){
	t [x].l = l , t [x].r = r ;
	if( l == r ){ t [x].data = k [l] ; printf( "%ld %ld\n" , l , t [x].data ) ; return ; }
	int mid = ( l + r ) >> 1 ;
	build( x << 1 , l , mid ) ; build( x << 1 | 1 , mid + 1 , r ) ;
	ud( x ) ;
}

inline int ask( int x , int l , int r ){ // 区间查询
//	printf( "%ld %ld %ld %ld\n" , x , t [x].data , t [x].l , t [x].r ) ;
	if( t [x].l >= l && t [x].r <= r ) return t [x].data ;
	sp( x ) ; int mid = ( t [x].l + t [x].r ) >> 1 , ans = 0x3f3f3f3f ; 
	if( l <= mid ) ans = min( ans , ask( x << 1 , l , r ) ) ;
	if( r > mid ) ans = min( ans , ask( x << 1 | 1 , l , r ) ) ; 
	return ans ;
}

inline void cge( int x , int l , int r , int w ){
	printf( "%ld %ld\n" , t [x].l , t [x].r ) ;
	if( t [x].l >= l && t [x].r <= r ){ t [x].lz = 1 , t [x].data = w ; return ; }
	sp( x ) ; int mid = ( t [x].l + t [x].r ) >> 1 ;
	if( l <= mid ) cge( x << 1 , l , r , w ) ;
	if( r > mid ) cge( x << 1 | 1 , l , r , w + ( mid - l ) ) ; 
	ud( x ) ;
}

inline void resv( int x , int l , int r , int w ){


}
 
void sc(){
	n = read() ; m = read() ;	
	for( R i = 1 ; i <= n ; i ++ ){
		scanf( "%c" , &ch ) ;
		int x = ch - 'a' + 1 ;
//		printf( "%ld\n" , x ) ;
		ins( rt , 1 , 26 , x , 1 ) ;
		a [i] = x ;
	} 
	for( R i = 1 ; i <= n ; i ++ ){
//		printf( "%ld\n" , a [i] ) ;
		add( a [i] ) ;
		k [i] = ask( a [i] ) ;
	}
	build( 1 , 1 , n ) ;
	
//	for( R i = 1 ; i <= n * 4 ; i ++ )
//		printf( "%ld %ld %ld %ld\n" , i , t [i].data , t [i].l , t [i].r ) ;
	
	for( R i = n ; i >= 1 ; i -- )
		st [++ top] = sr( rt , k [i] ) ;
	while( top ) printf( "%c" , ( char ) st [top --] + 'a' - 1 ) ; 
}

void work(){
	int ll , rr , opt ;
	while( m -- ){
		ll = read() , rr = read() , opt = read() ;
		int mn = ask( 1 , ll , rr ) ;
		if( opt ) cge( 1 , ll , rr , mn ) ;//, resv( 1 , ll , rr , mn ) ; // 降序:先升序,再颠倒
		else cge( 1 , ll , rr , mn ) ;
	} 	
}

signed main(){	
	sc() ;
	work() ;
	return 0 ;
}

正解是线段树优化了一个桶排序(\(\%DeepinC\)学长\(300ms\)代码)
普通桶排序应该是\(O(nm)\)的,利用这道题只有二十六个字母的性质,给每个区间建26个桶。
操作的时候查询区间内的桶然后分字母装好就行了。
但是这样常数有些大,\(\%\)土哥在向下递归的时候完成修改,这样就不用分字母了,不过需要打标记代表上升还是下降。

code


#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long
#define R register int
#define printf Ruusupuu = printf

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef unsigned long long G ;
const int N = 1e5 + 10 ;

int Ruusupuu ;

inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch ^ '0' ) , ch = getchar() ;
	return fg ? -w : w ;
}

int n , m , k [N] , a [N] , gnt , tnt , rt , x , mem [30] ;
struct T{ int data [30] , l , r , lz ; } t [N << 5] ;

inline void ud( int x ){ for( R i = 1 ; i <= 26 ; i ++ ) t [x].data [i] = t [x << 1].data [i] + t [x << 1 | 1].data [i] ; }
inline void sp( int x ){
	if( !t [x].lz ) return ;
	int ts = t [x].lz ; t [x].lz = 0 ;
	for( R i = 1 ; i <= 26 ; i ++ ) t [x << 1].data [i] = t [x << 1 | 1].data [i] = 0 ;
	
	t [x << 1].lz = ts , t [x << 1 | 1].lz = ts ;
	t [x << 1].data [ts] += ( t [x << 1].r - t [x << 1].l + 1 ) ;
	t [x << 1 | 1].data [ts] += ( t [x << 1 | 1].r - t [x << 1 | 1].l + 1 ) ;
}


inline void build( int x , int l , int r ){
	t [x].l = l , t [x].r = r ;
	if( l == r ){ t [x].data [a [l]] ++ ; return ; }
	int mid = ( l + r ) >> 1 ;
	build( x << 1 , l , mid ) ; build( x << 1 | 1 , mid + 1 , r ) ;
	ud( x ) ;
}
 
inline void ask( int x , int l , int r ){
//	printf( "%ld %ld %ld %ld\n" , t [x].l , t [x].r , l , r ) ;
	if( t [x].l >= l && t [x].r <= r ){ for( R i = 1 ; i <= 26 ; i ++ ) mem [i] += t [x].data [i] ; return ; }
	sp( x ) ; 
	int mid = ( t [x].l + t [x].r ) >> 1 ;
	if( l <= mid ) ask( x << 1 , l , r ) ;
	if( r > mid ) ask( x << 1 | 1 , l , r ) ; 
}
 
inline int asks( int x , int pos ){
	if( t [x].l == t [x].r ) { 
		for( R i = 1 ; i <= 26 ; i ++ )
			if( t [x].data [i] ) return i ;
	} 
	sp( x ) ; 
	int mid = ( t [x].l + t [x].r ) >> 1 ;
	if( pos <= mid ) return asks( x << 1 , pos ) ;
	else return asks( x << 1 | 1 , pos ) ;
} 
 
inline void cge( int x , int l , int r , int w ){
	
	if( t [x].l >= l && t [x].r <= r ){
//		printf( "C%ld %ld %ld %ld %ld\n" , t [x].l , t [x].r , l , r , w ) ;
		for( R i = 1 ; i <= 26 ; i ++ ) t [x].data [i] = 0 ;
		t [x].data [w] += ( t [x].r - t [x].l + 1 ) ;
//		printf( "%ld %ld %ld\n" , t [x].data [w] , w , t [x].l ) ;
		t [x].lz = w ; return ; 
	}
	sp( x ) ;
	int mid = ( t [x].l + t [x].r ) >> 1 ;
	if( l <= mid ) cge( x << 1 , l , r , w ) ;
	if( r > mid ) cge( x << 1 | 1 , l , r , w ) ;
	ud( x ) ;
} 
 
void sc(){
	n = read() ; m = read() ; char ch ;
	for( R i = 1 ; i <= n ; i ++ ){
		scanf( "%c" , &ch ) ;
		int x = ch - 'a' + 1 ; a [i] = x ;
	}  	build( 1 , 1 , n ) ;
//	for( R i = 1 ; i <= 26 ; i ++ ) printf( "%ld " , t [1].data [i] ) ;
//	for( R i = 1 ; i <= n * 4 ; i ++ )
//		printf( "%ld %ld %ld %ld\n" , i , t [i].data , t [i].l , t [i].r ) ;
}

void work(){
	int ll , rr , opt ;
	while( m -- ){
		ll = read() , rr = read() , opt = read() ;
		memset( mem , 0 , sizeof( mem ) ) ; 
		ask( 1 , ll , rr ) ;
//		for( R i = 1 ; i <= 26 ; i ++ ) printf( "%ld " , mem [i] ) ; puts( "" ) ; 
		if( opt ){
			int cnt = ll ;
			for( R i = 1 ; i <= 26 ; i ++ )
				if( mem [i] ) cge( 1 , cnt , cnt + mem [i] - 1 , i ) , cnt += mem [i] ;
		} 
		else{
			int cnt = ll ;
			for( R i = 26 ; i >= 1 ; i -- )
				if( mem [i] ) cge( 1 , cnt , cnt + mem [i] - 1 , i ) , cnt += mem [i] ;
		}
	} 
	
	for( R i = 1 ; i <= n ; i ++ ){
		x = asks( 1 , i ) ;
		printf( "%c" , ( char ) x + 'a' - 1 ) ;
	} puts( "" ) ;
}

signed main(){	
	sc() ;
	work() ;
	return 0 ;
}
土哥code


#include<bits/stdc++.h>
using namespace std;
#define ll long long

int n,m;
const int N=100005;
char s[N];
int l,r,x;

const int K=26;
#define ls x<<1
#define rs x<<1|1
#define lson ls,l,mi
#define rson rs,mi+1,r
#define mi ((l+r)>>1)
int v[N<<2][K]={0};
int lz[N<<2]={0};// 1 up 2 down
inline void up(int x){
	for(int i=0;i<26;i++)v[x][i]=v[ls][i]+v[rs][i];
}
inline void down(int x,int l,int r){ 
	if(!lz[x])return;
//	cout<<endl<<"DOWN "<<l<<' '<<r<<' '<<lz[x]<<endl;
//	for(int i=0;i<26;i++)cout<<v[x][i]<<' ';cout<<endl;
	int ln=mi-l+1;
	for(int i=0;i<26;i++)v[ls][i]=v[rs][i]=0;
	if(lz[x]==1){
		lz[ls]=lz[rs]=1;
		int pt=-1,now=0;
		int re=0;
		while(now<ln){
			++pt;
			if(now+v[x][pt]<=ln){
				v[ls][pt]=v[x][pt];
				now+=v[x][pt];
			}
			else{
				//cout<<"                     "<<ln<<' '<<now<<endl;
				v[ls][pt]=ln-now;
				re=v[x][pt]-v[ls][pt];
				break;
			}
//			cout<<now<<' '<<pt<<endl;
		}
		v[rs][pt]=re;
		for(int i=pt+1;i<26;i++)v[rs][i]=v[x][i];
	}
	else if(lz[x]==2){
		lz[ls]=lz[rs]=2;
		int pt=26,now=0;
		int re=0;
		while(now<ln){
			--pt;
			if(now+v[x][pt]<=ln){
				v[ls][pt]=v[x][pt];
				now+=v[x][pt];
			}
			else{
				v[ls][pt]=ln-now;
				re=v[x][pt]-v[ls][pt];
				break;
			}
		}
		v[rs][pt]=re;
		for(int i=pt-1;i>=0;i--)v[rs][i]=v[x][i];
	}
//	for(int i=0;i<26;i++)cout<<v[ls][i]<<' ';cout<<endl;
//	for(int i=0;i<26;i++)cout<<v[rs][i]<<' ';cout<<endl;
	lz[x]=0;
}
inline void build(int x,int l,int r){
	if(l==r){ v[x][s[l]-'a']++; return; }
	build(lson); build(rson); up(x); 
}
int tmp[K];
inline void get(int x,int l,int r,int nl,int nr){
//	cout<<"!! "<<l<<' '<<r<<endl;
//	for(int i=0;i<26;i++)cout<<v[x][i]<<' ';cout<<endl;
	if(nl<=l&&r<=nr){
		for(int i=0;i<26;i++)tmp[i]+=v[x][i];
		return;
	}
	down(x,l,r);
	if(mi>=nl)get(lson,nl,nr);
	if(mi<nr)get(rson,nl,nr);
}
//1 up 0 down
inline void upd(int x,int l,int r,int nl,int nr,int tl,int tr,int k){
	if(nl>nr)return;
	if(l>r)return;
	if(tl>tr)return;
//	cout<<"           "<<l<<' '<<r<<' '<<nl<<' '<<nr<<' '<<tl<<' '<<tr<<' '<<k<<endl;
	if(nl<=l&&r<=nr){
		if(k)lz[x]=1;
		else if(!k)lz[x]=2;
		int now=0,pt=0;
		for(int i=0;i<26;i++)v[x][i]=0;
//		cout<<"BMEOW ";for(int i=0;i<26;i++)cout<<v[x][i]<<' ';cout<<endl<<endl;
//		for(int i=0;i<26;i++)cout<<tmp[i]<<' ';cout<<endl;
		while(pt<26&&now+tmp[pt]<tl)now+=tmp[pt],pt++;
//		cout<<"KMEOW ";for(int i=0;i<26;i++)cout<<v[x][i]<<' ';cout<<endl<<endl;
		v[x][pt]=min(now+tmp[pt],tr)-tl+1;
		now+=tmp[pt],pt++;
		if(now>=tr)return;
//		cout<<"TMEOW ";for(int i=0;i<26;i++)cout<<v[x][i]<<' ';cout<<endl<<endl;
		while(pt<26&&now+tmp[pt]<=tr)now+=tmp[pt],v[x][pt]=tmp[pt],pt++;
		if(pt<26&&tr>=now)v[x][pt]=tr-now;
//		cout<<pt<<' '<<tr<<' '<<now<<endl;
//		cout<<"MEOW ";for(int i=0;i<26;i++)cout<<v[x][i]<<' ';cout<<endl;
//		cout<<l<<' '<<r<<' '<<nl<<' '<<nr<<' '<<tl<<' '<<tr<<' '<<k<<endl<<endl;
		return;
	}
	down(x,l,r);
	if(k==1){
		int lln=max(min(mi,nr)-nl,0)+1;
		int rln=max(nr-max(nl,mi+1),0)+1;
		//cout<<lln<<' '<<tm<<endl;
		//assert(tm<=tr);
		if(mi>=nl)upd(lson,nl,min(nr,mi),tl,tl+lln-1,k);
		if(mi<nr)upd(rson,max(nl,mi+1),nr,tr-rln+1,tr,k);
	}
	else if(k==0){
		int lln=max(min(mi,nr)-nl,0)+1;
		int rln=max(nr-max(nl,mi+1),0)+1;
		//cout<<lln<<' '<<tm<<endl;
		if(mi>=nl)upd(lson,nl,min(nr,mi),tr-lln+1,tr,k);
		if(mi<nr)upd(rson,max(nl,mi+1),nr,tl,tl+rln-1,k);
	}
	up(x);
}
inline void print(int x,int l,int r){
	if(l==r){
		for(int i=0;i<26;i++)if(v[x][i]){
			putchar('a'+i);
			break;
		}
		return;
	}
	down(x,l,r);
	print(lson); print(rson);
}

inline int read(){
	int f=0,s=0; char c=getchar();
	while(c>'9'||c<'0')f=(c=='-'),c=getchar();
	while(c>='0'&&c<='9')s=(s<<3)+(s<<1)+(c^'0'),c=getchar();
	return f?-s:s;
}

int main(){
	n=read(); m=read();
	scanf("%s",s+1);
	memset(v,0,sizeof v);
	build(1,1,n);
	while(m--){ //cout<<m<<endl;
		l=read(); r=read(); x=read();
		for(int i=0;i<26;i++)tmp[i]=0;
		get(1,1,n,l,r);
//		cout<<l<<' '<<r<<"   P ";for(int i=0;i<26;i++)cout<<tmp[i]<<' ';cout<<endl;
		upd(1,1,n,l,r,1,r-l+1,x);
//		while(1);
		//if(!m)while(1);
//		print(1,1,n); puts("");
	}
//	cout<<n<<endl;
	print(1,1,n); puts("");
	return 0;
}
posted @ 2021-06-09 07:15  Soresen  阅读(39)  评论(0)    收藏  举报