【ZJOI2013】K 大数查询 ( 树状数组套线段树 )

来源:互联网 发布:淘宝上金牌卖家可信吗 编辑:程序博客网 时间:2024/06/05 15:47

Description

有n 个位置和m 个操作。操作有两种,每次操作如果是1 a b c 的形式,表示往第a 个位置到第b 个位置每个位置加入一个数c。如果操作形如2 a b c 的形式,表示询问从第a 个位置到第b 个位置,第c 大的数是多少。

Input

在输入文件sequence.in 中,第一行两个数n,m。意义如题目描述。
接下来m 行每行形如1 a b c 或者2 a b c 如题目描述。

Output

在输出文件sequence.out 中,对于每个询问回答k 大数是多少。

Sample Input

2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3

Sample Output

1
2
1

Data Constraint

30%的数据n=m=1000
100%的数据n,m≤50000,并且后7 个点的数据n,m 的范围从32000 到50000近似成等差数列递增。a≤b≤n,1 操作中|c|≤n,2 操作中|c|≤maxlongint

嗯 , 应该要自然地想到二分答案 , 然后呢?
判定性问题 , 我想知道对于二分出的x,在区间l,r中有多少大于x的数的个数。
那应该想到开一个权值树状数组,里面套个线段树记录位置。
线段树要动态开节点, 为了方便, 我们不采取下传标记方式,比较麻烦。
对于线段树每个节点,(像昨天做的线段数套单调队列一样 )开两个变量,
cover 与pass
对于插入,遇到区间完整覆盖的,cover ++ , 对于路过的节点pass都加上其目标节点的区间大小( _r - _l + 1 )。
对于查询,遇到区间完整覆盖的,直接返回其pass值,其余非完整覆盖的,返回cover * ( _r - _l + 1 ) + Ask_Value_of_SubNode
这种线段树的打法避免了平常打法的复杂的标记。

#include<cstdio>#include<algorithm>#include<cstring>using namespace std ;#define N 50010#define lowbit( x ) x & -xint i , j , k , n , m , T ;struct SegmentTree {    int l , r ;    int cover , pass ;}tr[13183043] ;int rot[N] ;struct data {    int typ , c , a , b ;}a[N] ;struct rec {    int ps , va ;}d[N] ;bool cmp( rec a , rec b ) {    return a.va < b.va ;}int disva = 0 ;int demap[N] ;void SegIns( int l , int  r, int _l , int _r , int po ) {    int m = l + r >> 1 ;    tr[po].pass += _r - _l + 1 ;    if( _l==l && _r==r ) {        tr[po].cover +=  1 ;        return ;    }    if( _r<=m ) SegIns( l , m , _l , _r , ( tr[po].l==0 ? tr[po].l = ++ T : tr[po].l ) )  ;        else if( _l>m ) SegIns( m+1 , r , _l , _r , ( tr[po].r==0 ? tr[po].r = ++ T : tr[po].r ) ) ;            else SegIns( l , m , _l , m , ( tr[po].l==0 ? tr[po].l = ++ T : tr[po].l ) ) ,              SegIns( m+1 , r , m+1 , _r , ( tr[po].r==0 ? tr[po].r = ++ T : tr[po].r ) ) ;   }int SegAsk( int l , int r , int _l , int _r , int po ) {    int m = l + r >> 1 ;    if( po==0 ) return 0 ;    if( _l==l && _r==r ) return tr[po].pass  ;    if( _r<=m ) return SegAsk( l , m , _l , _r , tr[po].l ) + tr[po].cover * ( _r - _l + 1 )  ;        else if( _l>m ) return SegAsk( m+1 , r , _l , _r , tr[po].r ) + tr[po].cover * ( _r - _l + 1 ) ;            else return SegAsk( l , m , _l , m , tr[po].l ) +  SegAsk( m+1 , r , m+1 , _r , tr[po].r ) + tr[po].cover * ( _r - _l + 1 ) ;}void Insert( int x , int l , int r ) {    for( ;  x>0 ; x-=lowbit( x ) ) {        if( rot[x]==0 ) rot[x] = ++ T ;        SegIns( 1 , n , l , r , rot[x] ) ;    }}bool Ask( int x , int l , int r , int va ) {    int ret = 0 ;    for( ; x<=disva ; x+=lowbit( x ) ) {        ret += SegAsk( 1 , n , l , r , rot[x] ) ;    }    return ret >= va ;}int tot = 0 ;int main() {    scanf("%d%d",&n,&m ) ;    for( i=1 ; i<=m ; i++ ) {        scanf("%d%d%d%d",&a[i].typ , &a[i].a , &a[i].b , &a[i].c ) ;        if( a[i].typ==1 ) d[++tot].ps = i , d[tot].va = a[i].c ;    }    sort( d+1 , d+1+tot , cmp ) ;    d[0].va = -0x7fffffff ;    for( i=1 ; i<=tot ; i++ ) {        if( d[i].va != d[i-1].va ) ++disva , demap[ disva ] = d[i].va ;        a[ d[i].ps ].c = disva ;    }    for( i=1 ; i<=m ; i++ ) {        if( a[i].typ==1 ) {            // insert            Insert( a[i].c , a[i].a , a[i].b ) ;        } else {            int L = 1 , R = disva ;            while( L<=R ) {                int M = L+R >> 1 ;                if( Ask( M , a[i].a , a[i].b , a[i].c ) ) L = M + 1 ; else R = M - 1 ;            }            printf("%d\n",demap[R] ) ;        }    }}

Debuglog
把询问的c也离散化了。。。。。傻逼的可以

0 0