zoukankan      html  css  js  c++  java
  • 线段树复习+模板整理(8.2更新,未更新对应题目大意(懒) )

    一、区间覆盖(将某个区间的所有值变为某个值)+区间查询(求区间和)

      题目:HDU1698

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define lowbit(x) x&(-x)
    
    #define rep(i,l,r) for(int i=l;i<=r;++i)
    #define per(i,r,l) for(int i=r;i>=l;--i)
    
    #define ls o<<1
    #define rs o<<1|1
    #define lson L,mid,ls
    #define rson mid+1,R,rs
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5+10;
    const double eps = 1e-8;
    const double pi = acos(-1.0);
    int a[maxn];
    int sum[maxn<<2],lazy[maxn<<2];
    
    //更新区间o的值 此处为求和,即求左右区间的和
    void pushup(int o)
    {
        sum[o] = sum[ls]+sum[rs];//o*2 o*2+1
    }
    
    //建树,o节点为L~R开始往下建树
    void build(int L,int R,int o)
    {
        lazy[o] = 0;
        if(L==R)
        {
            //初始化操作,开始时最小区间长度均为1
            sum[o] = 1;
            return;
        }
        int mid = (R+L)>>1;
        build(lson);
        build(rson);
        //o的左右子树建立好后,向上更新节点o
        pushup(o);
    }
    
    void pushdown(int o,int len)
    {
        if(lazy[o])
        {
            lazy[ls] = lazy[rs] = lazy[o];//lazy向左右节点传递
    
            //左右子区间值更新 因为此处为区间覆盖 所以更新为lazy值*区间长度
            sum[ls] = lazy[o]*(len-len/2);
            sum[rs] = lazy[o]*(len/2);
    
            //o节点处lazy已向下传递,重置
            lazy[o] = 0;
        }
    }
    
    //将[l,r]区间的值更新为v,当前区间为[L,R],编号o
    void update(int l,int r,int L,int R,int o,int v)
    {
        if(l<=L&&R<=r)
        {
            //找到完全覆盖的区间[L,R],更新[L,R]的值,标记lazy[o]
            sum[o] = v*(R-L+1);
            lazy[o] = v;
            return ;
        }
        pushdown(o,R-L+1);
        int mid = (R+L)>>1;
        if(l<=mid) update(l,r,lson,v);
        if(r>mid) update(l,r,rson,v);
        pushup(o);
    }
    
    //求[l,r]的区间和,当前区间为[L,R],编号o
    int query(int l,int r,int L,int R,int o)
    {
        if(l<=L&&R<=r) return sum[o];
    
        pushdown(o,R-L+1);
        int mid = (R+L)>>1;
        int ret = 0;
        if(l<=mid) ret += query(l,r,lson);
        if(r>mid) ret += query(l,r,rson);
        return ret;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        rep(t,1,T)
        {
            int n;
            scanf("%d",&n);
            build(1,n,1);
            int q;
            scanf("%d",&q);
            rep(i,1,q)
            {
                int l,r,v;
                scanf("%d %d %d",&l,&r,&v);
                update(l,r,1,n,1,v);
            }
    
            int ans = query(1,n,1,n,1);
    
            printf("Case %d: The total value of the hook is %d.
    ",t,ans);
        }
    }
    View Code

    二、区间更新+区间查询(求区间最大值)

      题目:HDU3577

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define lowbit(x) x&(-x)
    
    #define rep(i,l,r) for(int i=l;i<=r;++i)
    #define per(i,r,l) for(int i=r;i>=l;--i)
    
    #define ls o<<1
    #define rs o<<1|1
    #define lson L,mid,ls
    #define rson mid+1,R,rs
    using namespace std;
    typedef long long ll;
    const int maxn = 1e6+10;
    const double eps = 1e-8;
    const double pi = acos(-1.0);
    int maxv[maxn<<2],lazy[maxn<<2];
    
    //更新区间o的值 此处为求最大值,即求左右区间的最大值
    void pushup(int o)
    {
        maxv[o] = max(maxv[ls],maxv[rs]);
    }
    
    //建树,o节点为L~R开始往下建树
    void build(int L,int R,int o)
    {
        lazy[o] = 0;
        if(L==R)
        {
            //初始化操作,开始时最小区间最大值均为0
            maxv[o] = 0;
            return;
        }
        int mid = (R+L)>>1;
        build(lson);
        build(rson);
        //o的左右子树建立好后,向上更新节点o
        pushup(o);
    }
    
    void pushdown(int o,int len)
    {
        if(lazy[o])
        {
            //lazy向左右节点传递
            lazy[ls] += lazy[o];
            lazy[rs] += lazy[o];
    
            //左右子区间值更新 因为此处为区间值+v 所以更新为 原值+lazy值
            maxv[ls] += lazy[o];
            maxv[rs] += lazy[o];
    
            //o节点处lazy已向下传递,重置
            lazy[o] = 0;
        }
    }
    
    //将[l,r]区间的值更新为v,当前区间为[L,R],编号o
    void update(int l,int r,int L,int R,int o,int v)
    {
        if(l<=L&&R<=r)
        {
            //找到完全覆盖的区间[L,R],更新[L,R]的值(最大值加v),标记lazy[o](lazy+v)
            maxv[o] += v;
            lazy[o] += v;
            return ;
        }
        pushdown(o,R-L+1);
        int mid = (R+L)>>1;
        if(l<=mid) update(l,r,lson,v);
        if(r>mid) update(l,r,rson,v);
        pushup(o);
    }
    
    //求[l,r]的区间最大值,当前区间为[L,R],编号o
    int query(int l,int r,int L,int R,int o)
    {
        if(l<=L&&R<=r) return maxv[o];
    
        pushdown(o,R-L+1);
        int mid = (R+L)>>1;
        int ret = 0;
        //合并左右区间最大值
        if(l<=mid) ret = max(ret,query(l,r,lson));
        if(r>mid) ret = max(ret,query(l,r,rson));
        return ret;
    }
    
    struct node
    {
        int l,r;
    }a[maxn];
    
    
    int ans[maxn];
    
    int main()
    {
        int T;
        scanf("%d",&T);
        rep(t,1,T)
        {
            int n = 0, k, q;
            scanf("%d %d", &k, &q);
            rep(i, 1, q)
            {
                scanf("%d %d", &a[i].l, &a[i].r);
                n = max(n, a[i].r - 1);
            }
    
            build(1, n, 1);
    
            int cnt = 0;
            rep(i, 1, q)
            {
                update(a[i].l, a[i].r-1, 1, n, 1, 1);
                //printf("%d %d
    ",i,query(a[i].l, a[i].r-1, 1, n, 1));
                if (query(a[i].l, a[i].r-1, 1, n, 1) > k) {
                    update(a[i].l, a[i].r-1, 1, n, 1, -1);
                } else {
                    ans[++cnt] = i;
                }
            }
    
            printf("Case %d:
    ", t);
            rep(i, 1, cnt)
            {
                printf("%d ",ans[i]);
            }
            printf("
    
    ");
        }
    }
    View Code

    三、区间更新+ 区间查询(区间求和)

      题目:HDU3468

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define lowbit(x) x&(-x)
    
    #define rep(i,l,r) for(int i=l;i<=r;++i)
    #define per(i,r,l) for(int i=r;i>=l;--i)
    
    #define ls o<<1
    #define rs o<<1|1
    #define lson L,mid,ls
    #define rson mid+1,R,rs
    using namespace std;
    typedef long long ll;
    const int maxn = 1e6+10;
    const double eps = 1e-8;
    const double pi = acos(-1.0);
    ll sum[maxn<<2],lazy[maxn<<2];
    
    ll a[maxn];
    
    //更新区间o 的值 此处为求和,即求左右区间的和
    void pushup(int o)
    {
        sum[o] = sum[ls]+sum[rs];
        //maxv[o] = max(maxv[ls],maxv[rs]);
    }
    
    //建树,o 节点为L~R开始往下建树
    void build(int L,int R,int o)
    {
        lazy[o] = 0;
        if(L==R)
        {
            //初始化操作,开始时最小区间和为本身
            sum[o] = a[L];
            return;
        }
        int mid = (R+L)>>1;
        build(lson);
        build(rson);
        //o 的左右子树建立好后,向上更新节点o
        pushup(o);
    }
    
    void pushdown(int o,int len)
    {
        if(lazy[o])
        {
            //lazy向左右节点传递
            lazy[ls] += lazy[o];
            lazy[rs] += lazy[o];
    
            //左右子区间值更新 因为此处为区间值+v 所以更新为 原值+lazy值*len
            sum[ls] += lazy[o]*(len-len/2);
            sum[rs] += lazy[o]*(len/2);
    
            //o节点处lazy已向下传递,重置
            lazy[o] = 0;
        }
    }
    
    //将[l,r]区间的值更新v(+v),当前区间为[L,R],编号o
    void update(int l,int r,int L,int R,int o,int v)
    {
        if(l<=L&&R<=r)
        {
            //找到完全覆盖的区间[L,R],更新[L,R]的值(和加上v*len),标记lazy[o](lazy+v)
            sum[o] += v*(R-L+1);
            lazy[o] += v;
            return ;
        }
        pushdown(o,R-L+1);
        int mid = (R+L)>>1;
        if(l<=mid) update(l,r,lson,v);
        if(r>mid) update(l,r,rson,v);
        pushup(o);
    }
    
    //求[l,r]的区间和,当前区间为[L,R],编号o
    ll query(int l,int r,int L,int R,int o)
    {
        if(l<=L&&R<=r) return sum[o];
    
        pushdown(o,R-L+1);
        int mid = (R+L)>>1;
        ll ret = 0;
        //合并左右区间的和
        if(l<=mid) ret += query(l,r,lson);
        if(r>mid) ret += query(l,r,rson);
        return ret;
    }
    
    
    
    int main()
    {
        int n,q;
        scanf("%d %d",&n,&q);
        rep(i,1,n)
        {
            scanf("%lld",&a[i]);
        }
        build(1,n,1);
    
        rep(i,1,q)
        {
            char s[2];
            int l,r,x;
            scanf("%s",s);
            //printf("%c
    ",s[0]);
            if(s[0]=='C')
            {
                scanf("%d %d %d",&l,&r,&x);
                update(l,r,1,n,1,x);
                //printf("c %d %d %d end
    ",l,r,x);
            }
            if(s[0]=='Q')
            {
                scanf("%d %d",&l,&r);
                //printf("q %d %d
    ",l,r);
                printf("%lld
    ",query(l,r,1,n,1));
            }
        }
    }
    View Code

    四、离散化+区间覆盖+单点查询(?)效率不够

      题目:POJ2528

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<set>
    #include<algorithm>
    #define lowbit(x) x&(-x)
    
    #define rep(i,l,r) for(int i=l;i<=r;++i)
    #define per(i,r,l) for(int i=r;i>=l;--i)
    
    #define ls o<<1
    #define rs o<<1|1
    #define lson L,mid,ls
    #define rson mid+1,R,rs
    using namespace std;
    typedef long long ll;
    const int maxn = 2e4+10;
    const double eps = 1e-8;
    const double pi = acos(-1.0);
    int sum[maxn<<2],lazy[maxn<<2];
    
    
    //更新区间o 的值 此处为求和,即求左右区间的和
    void pushup(int o)
    {
        sum[o] = sum[ls]+sum[rs];
        //maxv[o] = max(maxv[ls],maxv[rs]);
    }
    
    //建树,o 节点为L~R开始往下建树
    void build(int L,int R,int o)
    {
        lazy[o] = 0;
        if(L==R)
        {
            //初始化操作,开始时最小区间和为0
            sum[o] = 0;
            return;
        }
        int mid = (R+L)>>1;
        build(lson);
        build(rson);
        //o 的左右子树建立好后,向上更新节点o
        pushup(o);
    }
    
    void pushdown(int o,int len)
    {
        if(lazy[o])
        {
            //lazy向左右节点传递
            lazy[ls] = lazy[o];
            lazy[rs] = lazy[o];
    
            //左右子区间值更新 因为此处为区间覆盖 所以更新为 lazy值*len
            sum[ls] = lazy[o]*(len-len/2);
            sum[rs] = lazy[o]*(len/2);
    
            //o节点处lazy已向下传递,重置
            lazy[o] = 0;
        }
    }
    
    //将[l,r]区间的值更新为v,当前区间为[L,R],编号o
    void update(int l,int r,int L,int R,int o,int v)
    {
        if(l<=L&&R<=r)
        {
            //找到完全覆盖的区间[L,R],更新[L,R]的值(和更新为v*len),标记lazy[o](lazy=v)
            sum[o] = v*(R-L+1);
            lazy[o] = v;
            return ;
        }
        pushdown(o,R-L+1);
        int mid = (R+L)>>1;
        if(l<=mid) update(l,r,lson,v);
        if(r>mid) update(l,r,rson,v);
        pushup(o);
    }
    
    //求[l,r]的区间和,当前区间为[L,R],编号o
    int query(int l,int r,int L,int R,int o)
    {
        if(l<=L&&R<=r) return sum[o];
    
        pushdown(o,R-L+1);
        int mid = (R+L)>>1;
        int ret = 0;
        //合并左右区间的和
        if(l<=mid) ret += query(l,r,lson);
        if(r>mid) ret += query(l,r,rson);
        return ret;
    }
    
    int a[20010],t[20010];
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            int n = 0, q;
            scanf("%d", &q);
            rep(i, 0, q - 1) {
                scanf("%d %d", &a[2 * i], &a[2 * i + 1]);
                t[2 * i] = a[2 * i];
                t[2 * i + 1] = a[2 * i + 1];
            }
    
            sort(t, t + 2 * q);
            int m = unique(t, t + 2 * q) - t - 1;
            for (int i = 0; i < 2 * q; i++) {
                //printf("%d %d ",i,a[i]);
                a[i] = lower_bound(t, t+m, a[i])-t +1;
                //printf("%d
    ",a[i]);
            }
    
            rep(i, 0, q - 1) {
                n = max(n, a[i * 2 + 1]);
            }
            //printf("n=%d
    ", n);
            build(1, n, 1);
    
            //给第i 张海报赋值为i, 贴到对应区间,最后扫一遍区间统计出现的数有多少种就是有多少张海报可见
            rep(i, 0, q - 1) {
                update(a[2 * i], a[2 * i + 1], 1, n, 1, i + 1);
            }
    
            set<int> s;
            int ans = 0;
            rep(i, 1, n) {
                int tmp = query(i, i, 1, n, 1);
                if (tmp == 0) continue;
                if (s.find(tmp) == s.end()) {
                    ans++;
                    s.insert(tmp);
                }
            }
            printf("%d
    ", ans);
        }
    }
    View Code
  • 相关阅读:
    TCP/IP协议详解
    linux高性能服务器编程--初见
    聚合类
    类class 2
    继承
    构造函数再探
    静态成员与友元
    MySQL图形工具SQLyog破解版
    MySQL注释符号
    数据库中多对多关系的中间表的命名规则
  • 原文地址:https://www.cnblogs.com/WWkkk/p/9399949.html
Copyright © 2011-2022 走看看