POJ 3368 經典RMQ

下午開始寫,編寫邊看動漫,果然寫挫了,,晚上來debug,,,

題意:給一段不下降序列,,,求,l到r區間出現出現數字最多的數字的次數

思路:1,把相同的作爲一段,num表示該下標所在的段,left表示該段最左邊的下標,right表示該段最右邊的下標,value表示改下標的值,fmax用於求各個段的最大值

2,一邊情況是要求3段;l所在段;r所在段;在l和r中間的段(這段利用RMQ)  ;

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std ;

const int N = 100000 + 11 ;

struct Process {
	int num[N] ; int left[N] ; int right[N] ;
	int value[N] ;
	int fmax[N][30] ;
	int n , m , q ;

	void addinfo() {
		n = 1 ;
		scanf("%d" ,&value[1]) ;
		left[1] = 1 , right[1] = 1 ;
		num[1] = 1 ;
		fmax[1][0] = 1 ;
		for(int i = 2 ; i <= m ; ++i) {
			scanf("%d" ,&value[i]) ;
			if(value[i] == value[i-1]) {
				right[n] = i ;
				num[i] = n ;
				++fmax[n][0] ;
			}else {
				++n ;
				left[n] = right[n] = i ;
				num[i] = n ;
				fmax[n][0] = 1 ;
			}
		}
		for(int i = 1 ; (1<<i)<= n ; ++i) {
			for(int j = 1 ; j+(1<<i)-1 <= n ; ++j) {
				fmax[j][i] = max(fmax[j][i-1] , fmax[j+(1<<(i-1))][i-1]) ;
			}
		}
	}

	void query(int l , int r) {
		if(num[l] == num[r]) {
			printf("%d\n" , r-l+1) ;
			return ;
		}
		int a1 = right[num[l]] - l + 1 ;
		int a2 = r - left[num[r]] + 1 ;
		l = num[l] + 1 ;
		r = num[r] - 1 ;
		if(r < l ) {
			printf("%d\n" , max(a1 , a2)) ;
			return ;
		}
		int k = 0 ;
		while((1<<(k+1))<=r-l+1) ++k ;
		int a3 = max(fmax[l][k] , fmax[r-(1<<k)+1][k]) ;
		printf("%d\n" , max(max(a1 , a2),a3)) ;
	}

	void std_fun() {
		addinfo() ;
		int l , r ;
		for(int i = 0 ; i < q ; ++i) {
			scanf("%d%d" ,&l ,&r) ;
			query(l , r) ;
		}
	}
}p ;

int main() {//freopen("data.in" ,"r" ,stdin) ;
	while(scanf("%d" ,&p.m)==1 && p.m) {
		scanf("%d" ,&p.q) ;
		p.std_fun() ;
	}
}



發佈了48 篇原創文章 · 獲贊 5 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章