HDU - 1556 和1166,线段树的区间插入,单点查找和单点插入与区间查找

来源:互联网 发布:php各大视频解析源码 编辑:程序博客网 时间:2024/04/29 23:02

今天对最近几天学的线段树来总结一下。线段树解决的问题就是对查询的过程加快。
1.区间插入,单点查询。
HDU - 1556

#include <iostream>#include <cstdio>#define maxn 100005using namespace std;struct node{    int l,r,v;//l,r在这里代表的是左边的值和右边的值,v在这里维护的是被涂色的次数};node d[maxn<<2];void buildtree(int i,int l,int r)//建树{    d[i].l=l,d[i].r=r,d[i].v=0;    if(d[i].l==d[i].r)        return;    int mid=(d[i].l+d[i].r)/2;    buildtree(i<<1,l,mid);//位运算符,表示i*2    buildtree(i<<1|1,mid+1,r);//表示i*2+1}void Insert(int i,int a,int b)//因为是区间插入,然后找到一个区间{    if(d[i].l==a&&d[i].r==b)//找到了一个区间,为什么在这个区间++,那下面的具体的点呢?(答案在下面)    {        d[i].v++;        return;    }    int mid=(d[i].l+d[i].r)/2;    if(b<=mid) Insert(i<<1,a,b);     else if(a>=mid+1) Insert(i<<1|1,a,b);    else    {        Insert(i<<1,a,mid);        Insert(i<<1|1,mid+1,b);    }}int Count(int i,int a)//查询,单点查询{    if(d[i].l==d[i].r)//单点查询,所以是到某个具体的点    {        return d[i].v;    }    int mid=(d[i].l+d[i].r)/2;    if(a<=mid) return Count(i<<1,a)+d[i].v;//这里还是要加return的,如果函数返回类型是int的话,就是要返回值,不然的话,就会返回一些奇怪的东西。如果返回类型是void的话,递归的话,可以加return也可以不用。然后return是之间当前操作结束,所以如果后面要加其他操作的,就要注意下了。    else if(a>mid) return Count(i<<1|1,a)+d[i].v;//红色部分,这里也是一个小技巧,就是之前在某个区间v作为下面每个的次数的话,我们就可以在查询的时候加int main(){    int n;    while(scanf("%d",&n)!=EOF)    {        if(n==0)            break;             buildtree(1,1,n);        for(int i=0;i<n;i++)        {            int a,b;            scanf("%d %d",&a,&b);            Insert(1,a,b);        }        for(int i=1;i<n;i++)            printf("%d ",Count(1,i));        printf("%d\n",Count(1,n));    }    return 0;} 

2单点插入,区间和查询
题目 Hdu 1166 https://vjudge.net/problem/16216/origin

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define maxn 50005struct node{    int l,r,v;//因为查询的是区间和,所以V维护的是区间和};node d[maxn<<2];void buildtree(int i,int l,int r){    d[i].l=l,d[i].r=r;    if(l==r)    {        scanf("%d",&d[i].v);//这个是直接到了那个点的时候输入        return ;    }    int mid=(d[i].l+d[i].r)/2;    buildtree(i<<1,l,mid);    buildtree(i<<1|1,mid+1,r);    d[i].v=d[i<<1].v+d[i<<1|1].v;//相当于向上维护,注意这里是可以的,但是如果前面是 return buildtree()的时候就不行了,这一步就不会执行}void Insert(int i,int a,int v){    if(d[i].l==d[i].r)    {        d[i].v+=v;        return ;    }    int mid=(d[i].l+d[i].r)/2;    if(a<=mid) Insert(i<<1,a,v);    if (a>=mid+1) Insert(i<<1|1,a,v);    d[i].v=d[i<<1].v+d[i<<1|1].v;//插入之后,新增的会影响原来的,所以也要维护。}char q[10];int Count(int i,int l,int r){    if(d[i].l==l&&d[i].r==r)        return d[i].v;    int mid=(d[i].l+d[i].r)/2;    if(r<=mid)   return Count(i<<1,l,r);    else if(l>=mid+1) return Count(i<<1|1,l,r);    else return Count(i<<1,l,mid)+Count(i<<1|1,mid+1,r);//这个是在中间的情况}int main(){    int T,n;    scanf("%d",&T);    int temp=T;    while(T--)    {        memset(d,0,sizeof(d));        scanf("%d",&n);        buildtree(1,1,n);        int ans=0;        printf("Case %d:\n",temp-T);        while(scanf("%s",q)&&q[0]!='E')        {            int a,b;            scanf("%d %d",&a,&b);            if(q[0]=='A')                Insert(1,a,b);            if(q[0]=='S')                Insert(1,a,-b);            if(q[0]=='Q')            {                printf("%d\n",Count(1,a,b));            }        }    }    return 0;}

据说以上问题可以用树状数组来做,可是我还没开始学树状数组,下次学了之后用树状数组再来写一遍。

0 0
原创粉丝点击