hdu4638 1-n的一个全排列,q个询问,对于每个询问区间有多少个连续区间 : 技巧/离线/树状数组
随机开了场多校,题目挺好玩
题意化简下来就是比如有5 3 4 6 10 11,那么2-6里面有三个连续区间
假设一个区间都是独立的,就是最多有l-r+1个连续区间,然后我们要做的就是减去重复的
我们离线从左到右扫描原数组,只要a[i]-1出现在前面,那么就在这个位置+1,表示当前i这个不算独立,同理a[i]+1==
扫的时候每遇到一个询问就是查这个区间的和,用区间数(假设独立)-区间和(多算的独立点)就是这个询问的答案==
1 #include<stdio.h> 2 #include<string.h> 3 #include<vector> 4 #include<algorithm> 5 using namespace std; 6 vector<int>query[100005]; 7 int n,c[100005],a[100005],id[100005]; 8 struct dian{ 9 int l,r,ans; 10 }b[100005]; 11 int sum(int x) 12 { 13 int ret=0; 14 while (x>0) 15 { 16 ret+=c[x]; 17 x-=(x&-x); 18 } 19 return ret; 20 } 21 void add(int x,int d) 22 { 23 while (x<=n) 24 { 25 c[x]+=d; 26 x+=(x&-x); 27 } 28 } 29 int main() 30 { 31 int T,q,i,j; 32 scanf("%d",&T); 33 while (T--) 34 { 35 scanf("%d%d",&n,&q); 36 memset(id,-1,sizeof(id)); 37 for (i=1;i<=n;i++) query[i].clear(); 38 memset(c,0,sizeof(c)); 39 for (i=1;i<=n;i++) 40 { 41 scanf("%d",&a[i]); 42 id[a[i]]=i; 43 } 44 for (i=1;i<=q;i++) 45 { 46 scanf("%d%d",&b[i].l,&b[i].r); 47 query[b[i].r].push_back(i); 48 } 49 for (i=1;i<=n;i++) 50 { 51 if (id[a[i]-1]!=-1&&id[a[i]-1]<i) add(id[a[i]-1],1); 52 if (id[a[i]+1]!=-1&&id[a[i]+1]<i) add(id[a[i]+1],1); 53 for (j=0;j<query[i].size();j++) 54 b[query[i][j]].ans=(i-b[query[i][j]].l+1)- 55 (sum(i)-sum(b[query[i][j]].l-1)); 56 } 57 for (i=1;i<=q;i++) printf("%d\n",b[i].ans); 58 } 59 return 0; 60 }