现在的位置: 首页 > 综合 > 正文

【codeforces】484E. Sign on Fence 可持久化线段树

2017年10月15日 ⁄ 综合 ⁄ 共 2307字 ⁄ 字号 评论关闭

传送门:【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 ;
}

抱歉!评论已关闭.