1. 程式人生 > >CSU 1515 Sequence(莫隊演算法)

CSU 1515 Sequence(莫隊演算法)

Description
給出一個長度為n的序列ai,進行m次查詢,每次查詢區間[l,r]中滿足|ai-aj|=1的(i,j)對數(l<=i < j<=r)
Input
第一行為兩整數n和m表示序列長度和查詢次數,第二行n個整數ai表示該序列,最後m行每行兩個整數l和r表示查詢區間(1<=n<=10^4,1<=m<=10^5,0<=ai< 2^31)
Output
輸出每次查詢的答案
Sample Input
10 10
5 5 1 3 6 3 5 7 1 7
3 4
6 8
8 9
2 8
5 7
6 7
1 9
3 10
3 10
5 6
Sample Output


0
0
0
3
1
0
4
3
3
0
Solution
莫隊,給所有操作首先按左端點平方分塊,然後將每個區間左端點所處塊的編號為第一關鍵字,右端點為第二關鍵字排序,之後按順序在區間間遞推即可
Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
#define maxn 11111
struct node
{
    int l,r,id,ans;
}q[10*maxn
]
; int n,m,ans,a[maxn],pos[maxn]; map<int,int>cnt; int cmp1(node x,node y) { if(pos[x.l]!=pos[y.l])return x.l<y.l; return x.r<y.r; } int cmp2(node x,node y) { return x.id<y.id; } void update(int x,int v) { x=a[x]; cnt[x]+=v; ans+=cnt[x+1]*v; if(x)ans+=cnt[x
-1]*v; } int main() { while(~scanf("%d%d",&n,&m)) { cnt.clear(); int mm=(int)sqrt(n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); pos[i]=(i-1)/mm+1; } for(int i=0;i<m;i++) { scanf("%d%d",&q[i].l,&q[i].r); q[i].id=i; } sort(q,q+m,cmp1); ans=0; int l=1,r=0; for(int i=0;i<m;i++) { while(r<q[i].r)update(r+1,1),r++; while(r>q[i].r)update(r,-1),r--; while(l<q[i].l)update(l,-1),l++; while(l>q[i].l)update(l-1,1),l--; q[i].ans=ans; } sort(q,q+m,cmp2); for(int i=0;i<m;i++)printf("%d\n",q[i].ans); } return 0; }