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 }
View Code

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4638

posted on 2015-05-09 04:00  xiao_xin  阅读(423)  评论(0编辑  收藏  举报

导航