传送门:【codeforces】484E. Sign on Fence
题目分析:看了题解才会呢,感觉太巧妙了~
先对高度从高到低排序,然后构造可持久化线段树,每个节点保存一个高度下对应区间的左连续最大1个数,右连续最大1个数,区间最长连续1个数,然后查询一个区间内最长连续1长度就是线段树区间合并操作。每次询问【L,R,W】就是二分询问的高度(每个高度是一棵线段树),然后看询问区间的连续1个数是否大于等于W,大于就调整上界,否则调整下界(下标小的高度大,这样处理的好处是二分可以很轻易的写出来,直接就是lower_bound)。
不得不叹服啊,自己想了好一会儿也没想到可以转化成连续1来搞。。。
路还很长呢~
代码如下:
#include <map>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std ;
typedef long long LL ;
#define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define mid ( ( l + r ) >> 1 )
const int MAXN = 100005 ;
struct Node {
int h , pos ;
bool operator < ( const Node& a ) const {
return h > a.h ;
}
} node[MAXN] ;
struct Segment_Tree* null ;
struct Segment_Tree {
Segment_Tree* c[2] ;
//int sum ;
int Lmax ;
int Rmax ;
int Mmax ;
inline void modify ( int val ) {
c[0] = c[1] = null ;
Lmax = Mmax = Rmax = val ;
}
inline void push_up ( int l , int r ) {
int m = mid ;
//sum = c[0]->sum + c[1]->sum ;
Lmax = c[0]->Lmax ;
Rmax = c[1]->Rmax ;
Mmax = max ( max ( c[0]->Mmax , c[1]->Mmax ) , c[0]->Rmax + c[1]->Lmax ) ;
if ( Lmax == m - l + 1 ) Lmax += c[1]->Lmax ;
if ( Rmax == r - m ) Rmax += c[0]->Rmax ;
}
} ;
Segment_Tree pool[MAXN * 50] ;
Segment_Tree* cur ;
Segment_Tree* Root[MAXN] ;
int n ;
void init () {
cur = pool ;
null = cur ++ ;
null->modify ( 0 ) ;
}
void build ( Segment_Tree* &o , int l , int r ) {
o = cur ++ ;
o->modify ( 0 ) ;
if ( l == r ) return ;
int m = mid ;
build ( o->c[0] , l , m ) ;
build ( o->c[1] , m + 1 , r ) ;
}
void insert ( Segment_Tree* old , Segment_Tree* &now , int pos , int l , int r ) {
now = cur ++ ;
if ( l == r ) {
now->modify ( 1 ) ;
return ;
}
int m = mid ;
if ( pos <= m ) {
now->c[1] = old->c[1] ;
insert ( old->c[0] , now->c[0] , pos , l , m ) ;
} else {
now->c[0] = old->c[0] ;
insert ( old->c[1] , now->c[1] , pos , m + 1 , r ) ;
}
now->push_up ( l , r ) ;
}
int query ( Segment_Tree* o , int L , int R , int l , int r ) {
if ( L <= l && r <= R ) return o->Mmax ;
int m = mid ;
if ( R <= m ) return query ( o->c[0] , L , R , l , m ) ;
if ( m < L ) return query ( o->c[1] , L , R , m + 1 , r ) ;
int ans = max ( query ( o->c[0] , L , R , l , m ) , query ( o->c[1] , L , R , m + 1 , r ) ) ;
ans = max ( ans , min ( o->c[0]->Rmax , m - L + 1 ) + min ( o->c[1]->Lmax , R - m ) ) ;
return ans ;
}
int search ( int L , int R , int w ) {
int l = 1 , r = n ;
while ( l < r ) {
int m = mid ;
if ( query ( Root[m] , L , R , 1 , n ) >= w ) r = m ;
else l = m + 1 ;
}
return node[l].h ;
}
void solve () {
int l , r , w , m ;
init () ;
For ( i , 1 , n ) {
scanf ( "%d" , &node[i].h ) ;
node[i].pos = i ;
}
sort ( node + 1 , node + n + 1 ) ;
build ( Root[0] , 1 , n ) ;
For ( i , 1 , n ) {
insert ( Root[i - 1] , Root[i] , node[i].pos , 1 , n ) ;
}
scanf ( "%d" , &m ) ;
while ( m -- ) {
scanf ( "%d%d%d" , &l , &r , &w ) ;
printf ( "%d\n" , search ( l , r , w ) ) ;
}
}
int main () {
while ( ~scanf ( "%d" , &n ) ) solve () ;
return 0 ;
}