題目大意:題面意思不解釋了,轉換成數學模型,就是問一段區間[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 */