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;
}
$The \ light \ has \ betrayed \ me$

浙公网安备 33010602011771号