线段树相关

来源:互联网 发布:mac免费软件 编辑:程序博客网 时间:2024/06/18 06:46

这篇博文讲解的很详细,推荐:http://blog.csdn.net/zearot/article/details/48299459


HDU 1166,单点更新,区间求和

顺便说一下:把输入的字符串定义成string类型的,就会各种超时。不知道是为什么。。。

这里粘贴一下线段树单点更新的模板

#include<bits/stdc++.h>using namespace std;const int N = 50005;int num[N];int Seg[N<<2]; //应该为原数组的4倍大小//平衡二叉树中每个点存储的信息,本题为“和”void PushUp(int iNode) {    Seg[iNode] = Seg[iNode*2] + Seg[iNode*2+1];}//原始数据区间[l, r], 当前点为第iNode个点(iNode每次从1开始,根节点)void Build(int l, int r, int iNode) {    if(l == r) {        Seg[iNode] = num[l];        return;    }    int m = l + (r-l) / 2;    Build(l, m, iNode*2);    Build(m+1, r, iNode*2+1);    PushUp(iNode);}//原始数据区间[l, r], 在第k个点添加add,当前点为第iNode个点(iNode每次从1开始,根节点)void Update(int k, int add, int l, int r, int iNode) {    if(l == r) {        Seg[iNode] += add;        return;    }    int m = l + (r-l) / 2;    if (k <= m) {        Update(k, add, l, m, iNode*2);    }    else {        Update(k, add, m+1, r, iNode*2+1);    }    PushUp(iNode);}//原始数据区间[l, r](通常为[1, n],表示n个节点),当前查找的区间为[L, R],节点为iNodeint Query(int L, int R, int l, int r, int iNode) {    if (L<= l && r <=R)  {        return Seg[iNode];    }    int m = l + (r-l) / 2;    int sum = 0;    if (L <= m) {        sum += Query(L, R, l, m, iNode *2);    }    if (R > m) {        sum += Query(L, R, m+1, r, iNode*2+1);    }    return sum;}int main() {     int t, n, a, b;     char str[50];     cin>>t;     for(int j = 1; j <= t; j++)     {             cin>>n;           for(int j = 1; j <= n; j++) {                 scanf("%d",&num[j]);            }             Build(1,n,1);             printf("Case %d:\n",j);             while(cin>>str)             {                       if(!strcmp(str,"End"))                       {                                break;                       }                       if(!strcmp(str,"Add"))                       {                                scanf("%d%d",&a,&b);                                Update(a,b,1,n,1);                       }                       if(!strcmp(str,"Sub"))                       {                                scanf("%d%d",&a,&b);                                Update(a,-b,1,n,1);                       }                       if(!strcmp(str,"Query"))                       {                                scanf("%d%d",&a,&b);                                int ans=Query(a,b,1,n,1);                                printf("%d\n",ans);                       }             }     }   //  system("pause");     return 0;}



HDU 1698,区间更新,区间求和

附上模板代码(注:其实此题没有必要做Query操作,直接返回Seg[1]就行了,只是想实现下)
#include<bits/stdc++.h>using namespace std;const int N = 100010;int Seg[N<<2];int isAdd[N<<2]; //标记节点,用于延迟标记.标记的含义:本节点的统计信息已经根据标记更新过了,但是本节点的子节点仍需要进行更新。void PushUp(int iNode) {    Seg[iNode] = Seg[iNode*2] + Seg[iNode*2+1];}void Build(int l, int r, int iNode) {    if(l == r) {        Seg[iNode] = 1;        return;    }    int m = l + (r-l) / 2;    Build(l, m, iNode*2);    Build(m+1, r, iNode*2 + 1);    PushUp(iNode);}//iNode为当前节点,lCnt为当前节点左子树中叶子节点数量,rCnt对应右子树void PushDown(int iNode, int lCnt, int rCnt) {    if(isAdd[iNode]) {        //下推标记        isAdd[iNode * 2] = isAdd[iNode];        isAdd[iNode*2+1] = isAdd[iNode];        //修改子节点的Seg        Seg[iNode * 2] = (lCnt * isAdd[iNode]);        Seg[iNode * 2 + 1] = (rCnt * isAdd[iNode]);        //清楚本节点标记        isAdd[iNode] = 0;    }}//更新[L, R]区间的值为zvoid Update(int L, int R, int z, int l, int r, int iNode) {    if (L<=l && r<=R) {        Seg[iNode] = (r-l+1)*z;        isAdd[iNode] = z;        return;    }    int m = l + (r-l)/2;    PushDown(iNode, m-l+1, r-m);    if(L <= m) {        Update(L, R, z, l, m, iNode*2);    }    if(R > m) {        Update(L, R, z, m+1, r, iNode*2+1);    }    PushUp(iNode);}int Query(int L, int R, int l, int r, int iNode) {    if(L <= l && r <= R) {        return Seg[iNode];    }    int m = l + (r-l) / 2;    PushDown(iNode, m-l+1, r-m); //延迟标记的关键之处?在查询的时候继续向下标记    int sum = 0;    if(L<=m) {        sum += Query(L, R, l, m, iNode*2);    }    if(R> m) {        sum += Query(L, R, m+1, r, iNode*2+1);    }    return sum;}int main() {    int t;    cin >> t;    for(int i = 1; i <= t; i++) {        int n;        cin>> n;        memset(isAdd, 0, sizeof(isAdd));        Build(1, n, 1);        int q;        cin>>q;        int x, y, z;        while(q--) {            //cin >>x >> y >> z;            scanf("%d%d%d", &x, &y, &z);            Update(x, y, z, 1, n, 1);        }        cout<< "Case " <<i << ": The total value of the hook is " <<  Query(1, n, 1, n, 1) <<"."<<endl;    }    return 0;}