HDU4638

  1 /*树状数组求和,一边询问一边维护,离线处理*/
  2 #include<stdio.h>
  3 #include<algorithm>
  4 #include<string.h>
  5 using namespace std;
  6 const int maxn=100000+10;
  7 struct point
  8 {
  9     int l,r,index;
 10 }node[maxn];
 11 int a[maxn];
 12 int num[maxn];
 13 int index[maxn];
 14 int result[maxn];
 15 int n,m;
 16 bool cmp(const point a,const point b)
 17 {
 18     return a.l<b.l;
 19 }
 20 int lowbit(int x)
 21 {
 22     return x&(-x);
 23 }
 24 void updata(int x,int v)//修改
 25 {
 26     while(x<=n)
 27     {
 28        a[x]=a[x]+v;
 29        x=x+lowbit(x);//在修改的时候往右往上爬
 30     }
 31 }
 32 int sum(int x)//求和
 33 {
 34     int ans=0;
 35     while(x>0)
 36     {
 37         ans=ans+a[x];
 38         x=x-lowbit(x);//求和的时候,往左往上爬
 39     }
 40     return ans;
 41 }
 42 int main()
 43 {
 44     int i,j;
 45     int t;
 46     scanf("%d",&t);
 47     while(t--)
 48     {
 49         scanf("%d%d",&n,&m);
 50         for(i=1;i<=n;i++)
 51         {
 52             scanf("%d",&num[i]);
 53             index[num[i]]=i;
 54         }
 55         memset(a,0,sizeof(a));
 56         index[0]=n+10; index[n+1]=n+10;//边界处理
 57         for(i=1;i<=n;i++)
 58         {
 59             if(i<index[num[i]-1] && i<index[num[i]+1])//说明新插入的a[i],前面还没有和他构成连续的数,那么插入a[i]必然是段数增加1
 60                 updata(i,1);
 61             else if(i>index[num[i]-1] && i>index[num[i]+1])//说明新插入的a[i],前面有和他构成连续的数,因为以前a[i]-1和a[i]+1这些已经加了1,所以减去1,是使得这三个数的段贡献是1
 62                 updata(i,-1);
 63         }
 64          for(i=0;i<m;i++)//离线处理
 65          {
 66              scanf("%d%d",&node[i].l,&node[i].r);
 67              node[i].index=i;
 68          }
 69          sort(node,node+m,cmp);//按查询的左区间从小到大排
 70          i=1;
 71          j=0;
 72          while(j<m)//一边询问一边修改
 73          {
 74              while(i<=n && node[j].l>i)//因为每个节点i都属于一个人以它自身结尾的水平长条这样区间询问求和的时候会加上一些多余的数,所以要处理
 75              {
 76                  if(i>index[num[i]-1] && i>index[num[i]+1])//将包含i的节点删去1个段,因为i你不在询问区间内
 77                      updata(i,-1);
 78                  else if(i<index[num[i]-1] && i<index[num[i]+1])//不包含i的在询问的时候肯定段数加1
 79                  {
 80                      updata(i,-1);
 81                      updata(index[num[i]-1],1);
 82                      updata(index[num[i]+1],1);
 83                  }
 84                  else if(i<index[num[i]-1])
 85                  {
 86                      updata(i,-1);
 87                      updata(index[num[i]-1],1);
 88                  }
 89                  else if(i<index[num[i]+1])
 90                  {
 91                      updata(i,-1);
 92                      updata(index[num[i]+1],1);
 93                  }
 94                 i++;
 95              }
 96              while(j<m && node[j].l<=i)//处理起点相同的询问
 97              {
 98                  result[node[j].index]=sum(node[j].r);
 99                  j++;
100              }
101          }
102          for(i=0;i<m;i++)
103          {
104              printf("%d
",result[i]);
105          }
106     }
107     return 0;
108 }
原文地址:https://www.cnblogs.com/okboy/p/3231970.html