首页 > 其他 > 详细

线段树

时间:2015-04-24 00:57:51      阅读:259      评论:0      收藏:0      [点我收藏+]
Problem Description
There are n men ,every man has an ID(1..n).their ID is unique. Whose ID is i and i-1 are friends, Whose ID is i and i+1 are friends. These n men stand in line. Now we select an interval of men to make some group. K men in a group can create K*K value. The value of an interval is sum of these value of groups. The people of same group‘s id must be continuous. Now we chose an interval of men and want to know there should be how many groups so the value of interval is max.
 
Input
First line is T indicate the case number. For each case first line is n, m(1<=n ,m<=100000) indicate there are n men and m query. Then a line have n number indicate the ID of men from left to right. Next m line each line has two number L,R(1<=L<=R<=n),mean we want to know the answer of [L,R].
 
Output
For every query output a number indicate there should be how many group so that the sum of value is max.
 
Sample Input
1
5 2
3 1 2 5 4
1 5
2 4
 
Sample Output
1 2
题意:给你一个1~N的排列,问区间[L, R] 之间有多少段连续的数。比如3 1 2 5 4 区间[1,5],就是连续的一段,区间[2,4],就是1,2和5  这两段。
离线处理每个查询,遍历每个点,设当前处理的区间终点为R,处理每个查询的时候,首先假设所有的数a[i]都是自己独立成段,如果有a[i]+1,或者a[i]-1的数在区间[L,R]内,那么它肯定不是独立成段的,也就是我们要减去在[L,R]内不独立成段的数的个数。我们用mark[i]记录数字i现的位置,也就是对于每次查询,我们要判断的就是a[i]-1和a[i]+1是不是在在[1,i]之间出现过,如果出现过一个,就加0,两个都出现了,那么连续的段数就减1,两个都没有出现,连续的段数就加1。(不妨在纸上画一下试试?)上代码

#include <iostream>

#include <cstring>

#include <cstdio>

#include <algorithm>

using namespace std;

#define lson l,m,rt<<1

#define rson m+1,r,rt<<1|1

const int MAX=100010;

struct point {   int l,r,id; } q[MAX];

int n,m;

int sum[MAX<<2];

int val[MAX];

int mark[MAX];

int ans[MAX];

void putup(int rt)

{   sum[rt]=sum[rt<<1]+sum[rt<<1|1]; }

void build(int l,int r,int rt)

{  sum[rt]=0;    

  if (l==r)      

   return ;     

  int m=(l+r)>>1;  

  build(lson);   

  build(rson);

}

void update(int k,int v,int l,int r,int rt)

{     if (l==r)    

     {  

    m[rt]+=v;      

   return ;  

     }         

int m=(l+r)>>1;    

if (k<=m)       

  update(k,v,lson);    

else    update(k,v,rson);   

  putup(rt); }

int query(int L,int R,int l,int r,int rt)

{    

if (L<=l&&r<=R)        

return sum[rt];    

int m=(l+r)>>1;    

int ret=0;    

if (L<=m)  ret+=query(L,R,lson);    

if (R>m)   ret+=query(L,R,rson);    

return ret;

}

bool cmp(point a,point b)//按照区间右端点排序

{     return a.r<b.r; }

int main()

{     int T;    

   scanf("%d",&T);   

  while (T--)    

{  scanf("%d%d",&n,&m);      

   build(1,n,1);//建树       

   for (int i=1;i<=n;i++)       

   scanf("%d",&val[i]);//读入值        

   for (int i=1;i<=m;i++)//m次访问       

  {  

     anf("%d%d",&q[i].l,&q[i].r);//左右区间   

     q[i].id=i;//记录为第i次访问        

  }   

   sort(q+1,q+m+1,cmp);   

   memset(mark,0,sizeof(mark));//初始化

   int cur=1;     

   for (int i=1;i<=n;i++)    

     {           

        update(i,1,1,n,1);  

        if (mark[val[i]+1]!=0)//右边出现了     

        update(mark[val[i]+1],-1,1,n,1);         

        if (mark[val[i]-1]!=0)//左边出现了                

        update(mark[val[i]-1],-1,1,n,1);                 //每一次更新一个右区间,先加上1,如果左右同时出现了,最终就是减了1,只出现一个,就是没变,没出现,就是0            

        mark[val[i]]=i;//记录val[i]的位置        

     while (cur<=m&&q[cur].r<=i)//对最终结果确定值        

     {            

        ns[q[cur].id]=query(q[cur].l,q[cur].r,1,n,1);//第i次访问的结果,是其左右端点的访问的结果         

        cur++;            

     }        

    for (int i=1;i<=m;i++)          

      printf("%d\n",ans[i]);    

}

return 0 ;

}

 

线段树

原文:http://www.cnblogs.com/osiris53719/p/4452139.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!