程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> hdu 4638 Group

hdu 4638 Group

編輯:C++入門知識

題目大意:題面意思不解釋了,轉換成數學模型,就是問一段區間[l,r]有幾段連續的數,比如[2,3,1,4,6,7]那麼這段區間內有兩段,分別是1,2,3,4和6,7。

解題思路:由於詢問次數有100000次,所以我們直接處理[l,r]顯然不行。線段樹在線似乎也是做不了的。可以想到的是,如果我們從左到右一個個加進來,那麼對於加進來的第i個數num[i],那麼它就能增加一個段(num[i]+1,和num[i]-1在之前都沒出現過),或者減少一個段(num[i]+1,和num[i]-1在之前都出現過),或者不增不減(num[i]+1,和num[i]-1在之前只出現過其中一個)。那麼我們要找的詢問的區間[l,r]內有多少個區間,就是詢問[l,r]內的數,增加了幾個這樣的段。但是直接詢問[l,r]內的數產生的段數是不可以的,因為對於[l,r]內的某一個數,有可能它所能產生的段數是跟l之前,或者r之後的數有關的。因此我們可以將詢問離線出來,按l排好序,每次詢問之前,將l之前的數產生的影響先清除掉,也就是對於某個在l之前的數,將它所能影響的後面的數能增加的段去除,對於之前的已經不用管了,因為我們按左端點排序,所以在清除某一個數時,它前面的數的影響之前已經處理掉了。然後從上一次插完的位置開始到r,把這之間的數插進去,如果上一次已經超過r了,也沒關系,我們會答r之前的總後就可以了,而l之前的數已經被清除掉,所以這個前綴後自然就是[l,r]的區間和。

 

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std ;

const int maxn = 111111 ;

struct Query
{
	int l , r , ans ;
} p[maxn] ;
int pos[maxn] , vis[maxn] , c[maxn] , cnt[maxn] ;

int lowbit ( int x ) { return x & ( -x ) ; }

void update ( int pos , int v )
{
	while ( pos < maxn - 10 )
	{
		c[pos] += v ;
		pos += lowbit ( pos ) ;
	}
}

int query ( int pos )
{
	int ret = 0 ;
	while ( pos > 0 )
	{
		ret += c[pos] ;
		pos -= lowbit ( pos ) ;
	}
	return ret ;
}

int cmp ( int i , int j )
{
	return p[i].l < p[j].l ;
}

int num[maxn] ;
int main ()
{
	int i , j , k , m , n , cas ;
	scanf ( "%d" , &cas ) ;
	while ( cas -- )
	{
		scanf ( "%d%d" , &n , &m ) ;
		for ( i = 1 ; i <= n ; i ++ ) scanf ( "%d" , &num[i] ) ;
		for ( i = 1 ; i <= m ; i ++ )
		{
			scanf ( "%d%d" , &p[i].l , &p[i].r ) ;
			pos[i] = i ;
		}
		memset ( vis , 0 , sizeof ( vis ) ) ;
		memset ( c , 0 , sizeof ( c ) ) ;
		memset ( cnt , 0 , sizeof ( cnt ) ) ;
		sort ( pos + 1 , pos + m + 1 , cmp ) ;
		int last1 = 1 , last2 = 1 ;
		for ( i = 1 ; i <= m ; i ++ )
		{
			while ( last1 <= p[pos[i]].r )
			{
				int add = 1 ;
				if ( vis[num[last1]-1] ) add -- ;
				if ( vis[num[last1]+1] ) add -- ;
				vis[num[last1]] = 1 ;
				cnt[num[last1]] = last1 ;
				update ( last1 , add ) ;
				last1 ++ ;
			}
			while ( last2 < p[pos[i]].l )
			{
				if ( vis[num[last2]-1] ) update ( cnt[num[last2]-1] , 1 ) ;
				if ( vis[num[last2]+1] ) update ( cnt[num[last2]+1] , 1 ) ;
				update ( cnt[num[last2]] , -1 ) ;
				vis[num[last2]] = 0 ;
				last2 ++ ;
			}
			p[pos[i]].ans = query ( p[pos[i]].r ) ;
		}
		for ( i = 1 ; i <= m ; i ++ )
			printf ( "%d\n" , p[i].ans ) ;
	}
}
/*
10
10 5
1 3 5 7 9 2 4 6 8 10
1 10
2 9
3 8
4 7
5 6

10 5
1 3 5 7 9 10 8 6 4 2
1 10
2 9
3 8
4 7
5 6

10 5
1 2 3 4 5 6 7 8 9 10
1 10
2 9
3 8
4 7
5 6
*/

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved