Solution to a problem --Dynamic Rankings (Fenwick tree + Chairman of the tree)

Solution to a problem --Dynamic Rankings (Fenwick tree + Chairman of the tree)

This question can be a whole half, but I wrote a set of tree tree
and this tree is not so obvious outer


Topic Portal

Given a sequence comprising n number of a [1], a [2], [3] ...... a [n] a, must answer the inquiry procedure: for a given i, j, k, in a [ i], a [i + 1], a [i + 2] ...... a [j] in the k-th smaller number is the number (1≤k≤j-i + 1), and you can change the number of a [ i] value, after the change, the program can continue to answer the above questions for a later change. You need to compile such a program, a sequence of reads from the input file, and reads the series of instructions, including instructions and a modification instruction interrogation.

The first line has two positive integers n (1≤n≤100000), m (1≤m≤100000). Respectively represent the number and length of the instruction sequence.

The second row has the number n, represents a [1], a [2] ...... a [n], these numbers are less than 10 ^ 9. The following description of each instruction m rows, each row format is one of two formats. Q ijk or C it

Q ijk (i, j, k is a number, 1≤i≤j≤n, 1≤k≤j-i + 1) represents inquiry command to inquire about a [i], a [i + 1] ...... a [j the number of small k] in.

C (1≤i≤n, 0≤t≤10 ^ 9) represents the a [i] becomes changed t.

Simplify the meaning of problems

Modified with single point K-th small section (large)

Static on the K-large (Chairman of the tree)

The default is the Chairman of the tree you just go over, explain in detail in the code
is the original array of discrete, each state is a new weight segment tree, prefix and maintain a similar thing, because the same every time many part, with space saving can be considered persistent segment tree (only open one strand each).

AC code (static):

#include<bits/stdc++.h>
using namespace std;
const  int  MAXN = 1000005 ;  
inline int read(){
    int s = 0,w = 1;char g = getchar();while(g<'0'||g>'9'){if(g=='-')w*=-1;g = getchar();}
    while(g>='0'&&g<='9'){s = s*10+g-'0';g = getchar();}return s*w;
}
int  b[ MAXN ] , a [ MAXN ] , root[ MAXN ] ;
int  N , M , cnt = 0 ;
struct Segment{
    int  ls , rs , num ;
}t[ MAXN<<5 ] ; 
void copyNode( int x , int y ){
    t[ x ].ls = t[ y ].ls , t[ x ].rs = t[ y ].rs , t[ x ].num = t[ y ].num+1 ;
}
void build( int p , int  l , int  r ){//初始建树
    t[ p ].num = 0 ;
    if( l == r )return ;
    int  mid = ( l+r )>>1 ;
    build( t[ p ].ls = ++cnt , l , mid ) ;
    build( t[ p ].rs = ++cnt , mid+1 , r ) ;
}
int New_made( int las , int  l , int r , int pos ){//新建,las为上一状态
    int p = ++cnt ; 
    copyNode( p , las ) ;//新建的链深=树深,别想多了 
    if( l == r )return p ;
    int mid = ( l+r )>> 1 ; 
    if( pos <= mid )t[ p ].ls = New_made( t[ p ].ls , l , mid , pos ) ;//二分查找
    else t[ p ].rs = New_made( t[ p ].rs , mid+1 , r , pos ) ;
    return p ; 
}
int  ask( int x , int  y , int  l , int  r , int rank ){
    if( l == r )return l ;
    int  mid = (l+r)>>1 ;
    int  dif = t[ t[x].ls ].num - t[ t[y].ls ].num ;
    if( rank <= dif )ask( t[ x ].ls , t[ y ].ls , l , mid , rank ) ;//值域上二分
    else  ask( t[ x ].rs , t[ y ].rs , mid+1 , r , rank-dif ) ;
}
int main(){
    N = read() , M = read() ;//平时不用register了 
    for( int i = 1 ; i <= N ; ++i )b[ i ] = a[ i ] = read() ; 
    sort( b+1 , b+N+1 ) ;
    int  tot = unique( b + 1 , b + 1 + N ) - b - 1 ;//STL自带的去重 ,返回的是数组的尾地址
    build( root[0] = ++cnt , 1 , tot ) ; //root , l , r
    for( int i = 1 ; i <= N ; ++i ){//nlogn,等效Hash
        int pos = lower_bound( b+1 , b+tot+1 , a[ i ] ) - b ; 
        root[ i ] = New_made( root[i-1] , 1 , tot , pos ) ; // 上一版本root , l , r , pos  
    }
    for( int i = 1 ; i <= M ; ++i ){
        int m1 = read() , m2 = read() , m3 = read() ;
        int t = ask( root[ m2 ] , root[ m1-1 ] , 1 , tot , m3 ) ; //前缀和思想 
        printf("%d\n",b[ t ] ) ;
    }
    return 0 ;
}

On the Great Dynamic K (Fenwick tree sets Chairman of the tree)

Range sequence segment tree tree shape corresponding to ~ i when each of the above tree is a history of the state, i.e., the i-th tree represents the i-th state, and that maintains a prefix.

Then, with modifications, if simple modifications including the positions of all the prefix tree T fly obvious.

Then, some gods are not satisfied, since a prefix interval on each tree and sequences can correspond to each other, then why not like to maintain the same sequence number n Maintenance n trees Chairman tree with Fenwick tree it? (Please review the following figure)

Figure above c [1] ~ c [8] will correspond to a tree President. Then, each modification is to modify the log with a few trees, each inquiry is still two states, but each state will be composed by the log tree together. So ..... time and space complexity are NlogN ^ 2.

I write in a specific code of (refer to refer to, and finally wrote the board a good point)

#include<bits/stdc++.h>
using namespace std ;
const  int  MAXN = 100005 ;//log 16
inline int read(){
    int s = 0,w = 1;char g = getchar();while(g<'0'||g>'9'){if(g=='-')w*=-1;g = getchar();}
    while(g>='0'&&g<='9'){s = s*10+g-'0';g = getchar();}return s*w;
}
int  b[ MAXN*2 ] , a[ MAXN ] , root[ MAXN*18 ] ;
int  N , M  , cnt = 0 , totx = 0 , toty = 0  , xx[ 18 ] , yy[ 18 ] , tot = 0 ;
int  opa[ MAXN ] , opb[ MAXN ] , opc[ MAXN ] ;
char  op[ 20 ] ; 
struct  Segment{
    int ls , rs , num ;
}t[ MAXN*324 ] ; // 空间log^2 
void copyNode( int x , int y , int z ){
    if( x == 0 )return ; 
    t[ x ].ls = t[ y ].ls , t[ x ].rs = t[ y ].rs , t[ x ].num = t[ y ].num + z ;
}
int New_made( int las , int  l , int  r , int  pos , int val ){
    int  p = ++cnt  ;
    copyNode( p , las , val ) ;// las = 0 一样 
    if( l == r )return p ;
    int  mid = (l+r)>>1 ;
    if( pos <= mid )t[ p ].ls = New_made( t[ p ].ls , l , mid , pos , val ) ;
    else t[ p ].rs = New_made( t[ p ].rs , mid+1 , r , pos , val ) ;
    return p ;
}
int  query( int  l , int  r , int k ){//实现log棵树同时移动 
    if( l == r ) return l;
    int sum = 0 , mid = (l+r)/2; // sum是 log个 状态差 的和
    for( int i=1;i<=totx;i++) sum += t[t[ xx[i] ].ls].num ;
    for( int i=1;i<=toty;i++) sum -= t[t[ yy[i] ].ls].num ;
    if( sum >= k ){//二分,log棵树同时向下进入左区间或右区间,请读者自行脑补
        for(int i=1;i<=totx;i++) xx[i]=t[ xx[i] ].ls;
        for(int i=1;i<=toty;i++) yy[i]=t[ yy[i] ].ls;
        return query( l , mid , k ) ;
    }else{
        for(int i=1;i<=totx;i++) xx[i]=t[ xx[i] ].rs;
        for(int i=1;i<=toty;i++) yy[i]=t[ yy[i] ].rs;
        return query( mid+1 , r , k-sum ) ;
    }
}
void add( int x , int val ){//log次增加,就是多开了log条链
    int pos = lower_bound( b+1 , b+tot+1 , a[ x ] ) - b ; 
    for( int i = x ; i <= N ; i += i&-i )
    root[ i ] = New_made( root[ i ] , 1 , tot , pos , val ) ; // 上一版本root , l , r , pos  
}
int  ask( int x , int  y , int  z ){// 找出每次修改对应的log棵树
    totx = toty = 0 ;
    for( int j = y ; j ; j -=j&(-j) ) xx[++totx]=root[j];
    for( int j = x - 1 ; j ; j -=j&(-j) ) yy[++toty]=root[j];
    int ans = query( 1 , tot , z ) ;
    return b[ans] ;
}
int main(){
    N = read() , M = read() , tot = N ;
    for( int i = 1 ; i <= N ; ++i )b[ i ] = a[ i ] = read() ;
    for( int i = 1 ; i <= M ; ++i ){
        scanf("%s",op);
        opa[ i ] = read() , opb[ i ] = read() ;//离线后,方便进行离散化
        if( op[ 0 ]=='Q' )opc[ i ] = read() ;
        else b[ ++tot ] = opb[ i ] ; 
    }
    sort( b+1 , b+tot+1 ) ; 
    tot = unique( b+1 , b+tot+1 )-b-1 ; //离散化,同静态
    for( int i = 1 ; i <= N ; ++i )add( i , 1 ) ;
    for( int i = 1 ; i <= M ; ++i )
        if( opc[ i ] )printf("%d\n",ask( opa[ i ] , opb[ i ] , opc[ i ]) ) ;
        else {
            add( opa[ i ] , -1 ) ;//修改,树上对应的个数 -1 
            a[ opa[ i ] ] = opb[ i ] ;//序列上对应修改
            add( opa[ i ] , 1 ) ;//个数+1
        }
    return 0 ;
}

Then, remember to open space tree log ^ 2 times, do not like ssw02 as hung up.

Lack of this article, but please chiefs pointed out, ssw02 Thank you for reading.

Guess you like

Origin www.cnblogs.com/ssw02/p/11248065.html