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 & -x
int 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也离散化了。。。。。傻逼的可以