Room Test 1: string (tree line)

topic:

 

 

 

 analysis:

Violence: Every time intervals sort of violence.

Optimization: If you can know which character has a range, respectively, the number of these characters, you can press lexicographic enumeration directly, inserting them into the interval quickly.

Question has an important message: Only lowercase letters, that is, only 26 kinds of characters.

the first method:

It can be used to maintain a segment tree, where each node corresponds to 26 characters is stored in this interval. Each modification to query the statistics of the number of intervals for each character are asking.

Then modify section, see the specific code.

#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
#define N 100005
#define ri register int
int num[26][N*4],now[N*4],a[N],fl[N*4];
void update(int s) { for(ri i=0;i<26;++i) num[i][s]=num[i][s<<1]+num[i][s<<1|1]; }
void build(int s,int l,int r)
{
    FL [S] = - . 1 ;
     IF (L == R & lt) {NUM [A [L]] [S] = . 1 ; return ;} // one dimensional memory color, a one-dimensional memory segment tree node 
    build (s << . 1 , L, MID); Build (<< S . 1 | . 1 , MID + . 1 , R & lt); 
    Update (S); 
} 
void pushdown ( int S, int L, int R & lt) 
{ 
    IF (FL [S] == - . 1 ) return ;
     int tmp = MID-L + . 1 ;
     IF (FL [S] == . 1 ) { //Marker downstream is to the character first half of the ascending pass left section the latter half to the right section 
        int CNT = 0 , P = - . 1 ;
         the while (CNT <tmp) P ++, CNT + = NUM [P] [S], NUM [P] [<< S . 1 ] NUM = [P] [S], NUM [P] [<< S . 1 | . 1 ] = 0 ; 
        CNT - = tmp; 
        NUM [P] [S << . 1 ] - = CNT; NUM [P] [S << . 1 | . 1 ] + = CNT;
         for (P ++; P < 26 is ; P ++) NUM [P] [S << . 1 | . 1 ] = NUM [P] [S], NUM [P] [<< S . 1 ] = 0 ; 
    } 
    the else {
        int cnt=0,p=26;
        while(cnt<tmp) p--,cnt+=num[p][s],num[p][s<<1]=num[p][s],num[p][s<<1|1]=0;
        cnt-=tmp;
        num[p][s<<1]-=cnt; num[p][s<<1|1]+=cnt;
        for(p--;p>=0;p--) num[p][s<<1|1]=num[p][s],num[p][s<<1]=0;
    }
    fl[s<<1]=fl[s]; fl[s<<1|1]=fl[s]; fl[s]=-1;
}
void query(int s,int l,int r,int L,int R)
{
    if(L<=l && r<=R){
        for(ri i=0;i<26;++i) now[i]+=num[i][s]; return ;
    }
    pushdown(s,l,r);
    if(L<=mid) query(s<<1,l,mid,L,R);
    if(R>mid)  query(s<<1|1,mid+1,r,L,R);
}
void modify(int s,int l,int r,int L,int R,int op)
{
    if(l==r){
        int cnt=0,tmp=l-L+1,p;
        if(op){
            p=-1;
            while(cnt<tmp) p++,cnt+=now[p];
        }
        else{
            p=26;
            while(cnt<tmp) p--,cnt+=now[p];
        }
        for(ri i=0; I < 26 is ; I ++) [I] NUM [S] = 0 ; 
        NUM [P] [S] = . 1 ;
         return ; 
    } // I think this may not be required 
    IF (L <= R & lt && L <= R & lt) { 
        FL [S] = OP;
         int CNT = 0 , TMP1 = L-L + . 1 , TMP2 = R & lt-L + . 1 ; // draw a line segment appreciated that 
        for (RI I = 0 ; I < 26 is ; ++ I) NUM [I] [S] = 0 ;
         IF (OP) { // ascending 
            int P = - . 1 ;
             the while(CNT <TMP1) P ++, CNT = now + [P]; // start jump L l, hop character position with the ascending 
            NUM [P] [S] = CNT +-TMP1 . 1 ; // go out for a while to reduce off 
            the while (CNT <TMP2) P ++, NUM [P] [S] = now [P], CNT + = now [P]; // , sequentially in ascending order to modify character type this interval from l to R & lt 
            NUM [P] [ S] - = CNT-TMP2; // supra, subtracting out period to 
        }
         the else {
             int P = 26 is ;
             the while (CNT <TMP1) P -, + = CNT now [P]; 
            NUM [P] [S] TMP1-CNT + = . 1 ;
             the while (CNT <TMP2) P -, NUM [P] [S] = now [P], CNT + = now [P]; 
            NUM [P] [S]-=cnt-tmp2;
        }
        return ;
    }
    pushdown(s,l,r);
    if(L<=mid) modify(s<<1,l,mid,L,R,op);
    if(R>mid)  modify(s<<1|1,mid+1,r,L,R,op);
    update(s);
}
void print(int s,int l,int r)
{
    if(l==r){//递归到叶子节点输出 
        for(ri i=0;i<26;++i) if(num[i][s]) { printf("%c",i+'a'); break; }
        return ;
    }
    pushdown(s,l,r);
    print(s<<1,l,mid); print(s<<1|1,mid+1,r);
}
char s[N];
int main()
{
    freopen("string.in","r",stdin);
    freopen("string.out","w",stdout);
    int n,m,l,r,op;
    scanf("%d%d",&n,&m);
    scanf("%s",s);
    for(ri i=1;i<=n;++i) a[i]=s[i-1]-'a';
    build(1,1,n);
    while(m--){
        scanf("%d%d%d",&l,&r,&op);
        for(ri i=0;i<26;++i) now[i]=0;
        query(1,1,n,l,r);//统计区间中每种字符有多少个 
        modify(1,1,n,l,r,op);
    }
    print(1,1,n);
}
/*
5 2
cabcd
1 3 1
3 5 0

5
2
trlyo
1 4 1
1 1 0
*/
1

The second method:

Also a segment tree, but each node maintains that this interval is what kind of character, if this zone has a different character, that is 0.

When modifying or to the summation interval, then press for each character in ascending (or descending), such a character position if any, will be modified to correspond to it. When you modify a recursive changes to the piece they are the same kind of violence, and marking. pushdown time easier.

Compared to the first, the second method better grasp.

2

Guess you like

Origin www.cnblogs.com/mowanying/p/11604603.html