• 简单线段树


    一、单点更新

    hdu1166区间和

    #include <iostream>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    const int maxn=50005;
    const int maxnnode=1<<19;
    struct node{
        int value;
        int left,right;
    }node[maxnnode];
    
    int father[maxn];
    
    void BuidTree(int i,int l,int r)
    {
        node[i].left=l;
        node[i].right=r;
        node[i].value=0;
        if(l==r)
        {
            father[l]=l;
            return ;
        }
        BuidTree(i<<1,l,(int)floor((l+r)/2.0));
        BuidTree((i<<1)+1,(int)floor((l+r)/2.0+1),r);
    }
    
    void UpdataTree(int ri,int x)
    {
        if(ri==1)return;
        int fi=ri/2;
        node[fi].value+=x;
        UpdataTree(fi,x);
    }
    
    int res=0;
    
    void Query(int i,int l,int r)
    {
        if(node[i].left==l&&node[i].right==r)
        {
            res+=node[i].value;
            return;
        }
        i<<1;
        if(l<=node[i].right)
        {
            if(r<=node[i].right)
                Query(i,l,r);
            else
                Query(i,l,node[i].right);
        }
        i++;
        if(r<=node[i].left)
        {
            if(l<=node[i].left)
                Query(i,l,r);
            else
                Query(i,node[i].left,r);
        }
    }
    int main()
    {
        int t;
        cin >> t;
        while(t--){
            int n,tmp,k=1;
            cin >> n;
            BuidTree(1,1,n);
            for(int i=0;i<n;i++)
            {
                cin >> tmp;
                node[father[tmp]].value=tmp;
                UpdataTree(father[tmp],tmp);
            }
            cout << "Case " << k << ":" << endl;
            while(1)
            {
                string op;
                int a,b;
                cin >> op >> a >> b;
                if(op[0]=='Q')
                    Query(1,a,b);
                else if(op[0]=='S')
                    UpdataTree(father[a],-b);
                else if(op[0]=='A')
                    UpdataTree(father[a],b);
                else
                    break;
            }
            k++;
        }
        return 0;
    }

    二、区间更新

    POJ3468区间和,Lazy标记只有当操作到该节点时才将标价下放;

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    typedef long long ll;
    const int maxn=1e5+10;
    
    #define lson l,m,i<<1
    #define rson m+1,r,i<<1|1
    
    ll sum[maxn<<2],add[maxn<<2];        //区间和,区间结点增加值;
    
    struct Node{
        int l,r;
        int mid(){
            return (l+r)>>1;
        }
    }tree[maxn<<2];
    
    void PushUp(int rt)
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    
    void PushDown(int rt,int m)
    {
        if(add[rt]){                     //如果该区间结点标记存在,向下推移;
            add[rt<<1]+=add[rt];
            add[rt<<1|1]+=add[rt];
            sum[rt<<1]+=add[rt]*(m-(m>>1));
            sum[rt<<1|1]+=add[rt]*(m>>1);
            add[rt]=0;
        }
    }
    
    void BuidTree(int l,int r,int i)   //建树;
    {
        tree[i].l=l;
        tree[i].r=r;
        add[i]=0;
        if(l==r){
            scanf("%I64d",&sum[i]);
            return;
        }
        int m=tree[i].mid();
        BuidTree(lson);
        BuidTree(rson);
        PushUp(i);
    }
    void UpdataTree(int c,int l,int r,int rt)
    {
        if(tree[rt].l==l&&tree[rt].r==r){          //符合查询区间条件;
            add[rt]+=c;
            sum[rt]+=(ll)c*(r-l+1);
            return;
        }
        if(tree[rt].l==tree[rt].r)return;
        PushDown(rt,tree[rt].r-tree[rt].l+1);   //将标记下移;
        int m=tree[rt].mid();
        if(r<=m)UpdataTree(c,l,r,rt<<1);        //递归向下查找匹配区间;
        else if(l>m)
            UpdataTree(c,l,r,rt<<1|1);
        else{
            UpdataTree(c,l,m,rt<<1);
            UpdataTree(c,m+1,r,rt<<1|1);
        }
        PushUp(rt);
    }
    
    ll Query(int l,int r,int rt)
    {
        if(l==tree[rt].l&&r==tree[rt].r)return sum[rt];
        PushDown(rt,tree[rt].r-tree[rt].l+1);
        int m=tree[rt].mid();
        ll res=0;
        if(r<=m)res+=Query(l,r,rt<<1);          //匹配合适的查找区间;
        else if(l>m)res+=Query(l,r,rt<<1|1);
        else{
            res+=Query(l,m,rt<<1);
            res+=Query(m+1,r,rt<<1|1);
        }
        return res;
    }
    int main()
    {
        int n,m;
        while(~scanf("%d%d",&n,&m)){
            BuidTree(1,n,1);
            while(m--){
                char ch[3];
                int a,b,c;
                scanf("%s",ch);
                //cout << ch << endl;
                if(ch[0]=='Q')
                {
                    scanf(" %d %d",&a,&b,&c);
                    printf("%lld
    ",Query(a,b,1));
                }else{
                    scanf(" %d %d %d
    ",&a,&b,&c);
                    UpdataTree(c,a,b,1);
                }
            }
        }
        return 0;
    }

     三、线段树+离散化

    poj2528

    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    const int maxn=20005;
    const int MAX=1e7+5;
    #define lson left,m,rt<<1
    #define rson m+1,right,rt<<1|1
    //海报从后往前贴,避免后面的海报的干扰;
    int pl[maxn],pr[maxn];      //存区间端点
    int port[maxn],id[MAX];     //离散化端点
    bool covered[maxn<<2];      //存线段树的区间信息
    struct node{
        int l,r;
        int mid(){
            return (l+r)>>1;
        }
    }tree[maxn<<2];
    
    void BuidTree(int left,int right,int rt)
    {
        tree[rt].l=left;
        tree[rt].r=right;
        covered[rt]=false;
        if(left>=right)
            return ;
        int m=tree[rt].mid();
        BuidTree(lson);
        BuidTree(rson);
    }
    
    bool query(int left,int right,int rt)
    {
        if(covered[rt])return false;
        if(left==tree[rt].l&&right==tree[rt].r){
            covered[rt]=true;
            return true;
        }
        int m=tree[rt].mid();
        bool res;
        if(right<=m){
            res=query(left,right,rt<<1);
        }else if(left>m){
            res=query(left,right,rt<<1|1);
        }else{
            bool res1=query(left,m,rt<<1);
            bool res2=query(m+1,right,rt<<1|1);
            res=res1||res2;
        }
        if(covered[rt<<1]&&covered[rt<<1|1])    covered[rt]=true;
        return res;
    }
    int main()
    {
        int t,n;
        scanf("%d",&t);
        while(t--){
            int cnt=0,ans=0;
            scanf("%d",&n);
            for(int i=0;i<n;i++)
            {
                scanf("%d%d",&pl[i],&pr[i]);
                port[cnt++]=pl[i];
                port[cnt++]=pr[i];
            }
            sort(port,port+cnt);
            cnt=unique(port,port+cnt)-port;     //离散化;
            for(int i=0;i<cnt;i++)  id[port[i]]=i+1;
    
            BuidTree(1,cnt,1);
            for(int i=n-1;i>=0;i--){
                //cout << i <<endl;
                if(query(id[pl[i]],id[pr[i]],1)){
                    ans++;
                    //cout << ans << endl;
                }
            }
            cout <<ans << endl;
        }
        return 0;
    }

     离散化:有些数据本身很大, 自身无法作为数组的下标保存对应的属性。如果这时只是需要这堆数据的相对属性, 那么可以对其进行离散化处理。当数据只与它们之间的相对大小有关,而与具体是多少无关时,可以进行离散化。比如当你数据个数n很小,数据范围却很大时(超过1e9)就考虑离散化更小的值,能够实现更多的算法。

    //1.用数组离散
    for(int i=1;i<=n;i++){
        cin>>a[i].val;
        a[i].id = i;
    }
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++)
        b[a[i].id] = i;     //将a[i]数组映射成更小的值,b[i]就是a[i]对应的rank值
        
    //2.用STL+二分离散化
    for(int i=1;i<=n;i++){
        cin>>a[i];
        b[i] = a[i];
    }
    sort(b+1,b+1+n);
    int len = unique(b+1,b+1+n)-b-1;   //len就是去重之后的数组长度,unique用法可以去网上看看,用法简单
    for(int i=1;i<=n;i++)
        a[i] = lower_bound(b+1,b+1+n,a[i])-b;   //a[i]就是直接离散化出来的数组
  • 相关阅读:
    WinForm 窗体应用程序(初步)之一
    ADO.NET
    面向对象思想
    数据库原理
    HTML学习总结
    c# 学习心得(2)
    c# 学习心得(1)
    《大话数据结构》读书笔记(2)
    《大话数据结构》读书笔记(1)
    ASP.NET Core学习总结(3)
  • 原文地址:https://www.cnblogs.com/Cloud-king/p/9482920.html
Copyright © 2020-2023  润新知