线段树复习+模板整理(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
原文地址:https://www.cnblogs.com/WWkkk/p/9399949.html