[kuangbin带你飞]专题七 线段树 【A、B、C、E、G、H】

题目链接:点击打开链接

A - 敌兵布阵

HDU - 1166                    

单点更新及区间求和。

更新时是在原有的基础上进行加减,直接进行加减即可。

AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 50010;
long long ans;
struct node
{
    int l, r;
    int sum;
} tree[MAX<<2];

void pushup(int rt)
{
    tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}

void build(int l, int r, int rt)
{
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].sum = 0;
    if(l == r) //叶子结点
    {
        scanf("%d",&tree[rt].sum);
        return ;
    }
    int mid = (l+r)>>1;
    //递归建树
    build(l, mid, rt<<1);
    build(mid+1, r, rt<<1|1);
    pushup(rt);
}

void update(int pos, int val, int rt)
{
    //更新这个区间的值
    if(tree[rt].l == tree[rt].r)
    {
        tree[rt].sum += val;
        return ;
    }
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(pos <= mid)
        update(pos, val, rt<<1);
    else
        update(pos, val, rt<<1|1);
    pushup(rt);
}

void query(int x, int y, int rt)
{
    if(x == tree[rt].l && y == tree[rt].r)
    {
        ans += tree[rt].sum;
        return ;
    }
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(y <= mid)
        query(x, y, rt<<1);
    else if(x > mid)
        query(x, y, rt<<1|1);
    else
    {
        query(x, mid, rt<<1);
        query(mid+1, y, rt<<1|1);
    }
}
int main()
{
    int T;
    int n, pos, val;
    string s;
    scanf("%d",&T);
    for(int cas = 1; cas <= T; ++cas)
    {
        printf("Case %d:\n",cas);
        scanf("%d",&n);
        build(1, n, 1);
        while(cin >> s)
        {
            if(s == "End") break;
            scanf("%d%d",&pos,&val);
            if(s == "Add")
            {
                update(pos, val, 1);
            }
            else if(s == "Sub")
            {
                update(pos, -val, 1);
            }
            else if(s == "Query")
            {
                ans = 0;
                int x = pos;
                int y = val;
                if(x > y) swap(x, y);
                query(x, y, 1);
                cout << ans << endl;
            }
        }
    }
    return 0;
}


B - I Hate It

HDU - 1754                    

单点更新及区间最大值。

与A题不同的是,这里的单点更新是直接对数值进行替换,所以直接赋值即可。

AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 200010;
int ans;
struct node
{
    int l, r;
    int Max;
} tree[MAX<<2];

void pushup(int rt)
{
    tree[rt].Max = max(tree[rt<<1].Max, tree[rt<<1|1].Max);
}

void build(int l, int r, int rt)
{
    tree[rt].l = l;
    tree[rt].r = r;
    if(l == r) //叶子结点
    {
        scanf("%d",&tree[rt].Max);
        return ;
    }
    int mid = (l+r)>>1;
    //递归建树
    build(l, mid, rt<<1);
    build(mid+1, r, rt<<1|1);
    pushup(rt);
}

void update(int pos, int val, int rt)
{
    //更新这个区间的值
    if(tree[rt].l == tree[rt].r)
    {
        tree[rt].Max = val;
        return ;
    }
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(pos <= mid)
        update(pos, val, rt<<1);
    else
        update(pos, val, rt<<1|1);
    pushup(rt);
}

void query(int x, int y, int rt)
{
    if(tree[rt].l == x && tree[rt].r == y)
    {
        ans = max(ans, tree[rt].Max);
        return ;
    }
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(y <= mid)
        query(x, y, rt<<1);
    else if(x > mid)
        query(x, y, rt<<1|1);
    else
    {
        query(x, mid, rt<<1);
        query(mid+1, y, rt<<1|1);
    }
}
int main()
{
    int n, m;
    int x, y;
    string q;
    while(~scanf("%d%d",&n,&m))
    {
        build(1, n, 1);
        while(m--)
        {
            cin >> q >> x >> y;
            if(q == "Q")
            {
                ans = 0;
                query(x, y, 1);
                cout << ans << endl;
            }
            else
                update(x, y, 1);
        }
    }
    return 0;
}

C - A Simple Problem with Integers

POJ - 3468                    

区间更新及区间求和。

因为区间更新后的值不一定会一下子用到,所以进行延迟操作,通过lazy标记实现。

AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 100010;
struct node
{
    int l, r;
    long long sum, lazy;
} tree[MAX<<2];

void pushup(int rt)
{
    tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}

void pushdown(int rt) //延迟操作,更新当前结点的叶子
{
    int len = tree[rt].r - tree[rt].l + 1;
    tree[rt<<1].sum += tree[rt].lazy*(len-len/2);
    tree[rt<<1|1].sum += tree[rt].lazy*(len/2);
    tree[rt<<1].lazy += tree[rt].lazy;
    tree[rt<<1|1].lazy += tree[rt].lazy;
    tree[rt].lazy = 0;
}

void build(int l, int r, int rt)
{
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].sum = tree[rt].lazy = 0;
    if(l == r)
    {
        scanf("%lld",&tree[rt].sum);
        return ;
    }
    int mid = (l+r)>>1;
    //递归建树
    build(l, mid, rt<<1);
    build(mid+1, r, rt<<1|1);
    pushup(rt);
}

void update(int x, int y, long long val, int rt)
{
    //更新这个区间的值
    if(tree[rt].l == x && tree[rt].r == y)
    {
        tree[rt].lazy += val;
        tree[rt].sum += (y-x+1)*val;
        return ;
    }
    if(tree[rt].lazy)
        pushdown(rt);  //向下更新枝叶的值
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(y <= mid)
        update(x, y, val, rt<<1);
    else if(x > mid)
        update(x, y, val, rt<<1|1);
    else
    {
        update(x, mid, val, rt<<1);
        update(mid+1, y, val, rt<<1|1);
    }
    pushup(rt);
}

long long query(int x, int y, int rt)
{
    if(tree[rt].l == x && tree[rt].r == y)
        return tree[rt].sum;
    if(tree[rt].lazy)
        pushdown(rt);  //向下更新枝叶的值
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(y <= mid)
        return query(x, y, rt<<1);
    else if(x > mid)
        return query(x, y, rt<<1|1);
    else
        return query(x, mid, rt<<1) + query(mid+1, y, rt<<1|1);
}

int main()
{
    int n, m;
    int x, y;
    string q;
    while(~scanf("%d%d",&n,&m))
    {
        build(1, n, 1);
        while(m--)
        {
            cin >> q;
            scanf("%d%d",&x,&y);
            if(q == "Q")
            {
                cout << query(x, y, 1) << endl;
            }
            else
            {
                long long val;
                scanf("%lld",&val);
                update(x, y, val, 1);
            }
        }
    }
    return 0;
}


D - Mayor's posters

POJ - 2528                    


E - Just a Hook

HDU - 1698                    

区间更新(值替换)及区间求和,和C一样的做法,只不过在处理lazy及sum时 += 换为了 =。

AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 100010;
int ans;
struct node
{
    int l, r;
    int sum, lazy;
} tree[MAX<<2];

void pushup(int rt)
{
    tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}

void pushdown(int rt) //延迟操作,更新当前结点的叶子
{
    int len = tree[rt].r - tree[rt].l + 1;
    tree[rt<<1].sum = tree[rt].lazy*(len-len/2);
    tree[rt<<1|1].sum = tree[rt].lazy*(len/2);
    tree[rt<<1].lazy = tree[rt].lazy;
    tree[rt<<1|1].lazy = tree[rt].lazy;
    tree[rt].lazy = 0;
}

void build(int l, int r, int rt)
{
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].sum = tree[rt].lazy = 0;
    if(l == r)
    {
        tree[rt].sum = 1;
        return ;
    }
    int mid = (l+r)>>1;
    //递归建树
    build(l, mid, rt<<1);
    build(mid+1, r, rt<<1|1);
    pushup(rt);
}

void update(int x, int y, int val, int rt)
{
    //更新这个区间的值
    if(tree[rt].l == x && tree[rt].r == y)
    {
        tree[rt].lazy = val;
        tree[rt].sum = (y-x+1)*val;
        return ;
    }
    if(tree[rt].lazy)
        pushdown(rt);  //向下更新枝叶的值
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(y <= mid)
        update(x, y, val, rt<<1);
    else if(x > mid)
        update(x, y, val, rt<<1|1);
    else
    {
        update(x, mid, val, rt<<1);
        update(mid+1, y, val, rt<<1|1);
    }
    pushup(rt);
}

int query(int x, int y, int rt)
{
    if(tree[rt].l == x && tree[rt].r == y)
        return tree[rt].sum;
    if(tree[rt].lazy)
        pushdown(rt);  //向下更新枝叶的值
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(y <= mid)
        return query(x, y, rt<<1);
    else if(x > mid)
        return query(x, y, rt<<1|1);
    else
        return query(x, mid, rt<<1) + query(mid+1, y, rt<<1|1);
}

int main()
{
    int T;
    int n, m;
    int x, y, z;
    scanf("%d",&T);
    for(int i = 1; i <= T; ++i)
    {
        ans = 0;
        scanf("%d%d",&n,&m);
        build(1, n, 1);
        while(m--)
        {
            scanf("%d%d%d",&x,&y,&z);
            update(x, y, z, 1);
        }
        ans = query(1, n, 1);
        printf("Case %d: The total value of the hook is %d.\n",i,ans);
    }
    return 0;
}


F - Count the Colors

ZOJ - 1610                    


G - Balanced Lineup

POJ - 3264                    

查询区间最大值与最小值之差。

AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 200010;
int ans1, ans2;
struct node
{
    int l, r;
    int Max, Min;
} tree[MAX<<2];

void pushup(int rt)
{
    tree[rt].Max = max(tree[rt<<1].Max, tree[rt<<1|1].Max);
    tree[rt].Min = min(tree[rt<<1].Min, tree[rt<<1|1].Min);
}

void build(int l, int r, int rt)
{
    tree[rt].l = l;
    tree[rt].r = r;
    if(l == r) //叶子结点
    {
        scanf("%d",&tree[rt].Max);
        tree[rt].Min = tree[rt].Max;
        return ;
    }
    int mid = (l+r)>>1;
    //递归建树
    build(l, mid, rt<<1);
    build(mid+1, r, rt<<1|1);
    pushup(rt);
}

void update(int pos, int val, int rt)
{
    //更新这个区间的值
    if(tree[rt].l == tree[rt].r)
    {
        tree[rt].Max = tree[rt].Min = val;
        return ;
    }
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(pos <= mid)
        update(pos, val, rt<<1);
    else
        update(pos, val, rt<<1|1);
    pushup(rt);
}

void qMax(int x, int y, int rt)
{
    if(tree[rt].l == x && tree[rt].r == y)
    {
        ans1 = max(ans1, tree[rt].Max);
        return ;
    }
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(y <= mid)
        qMax(x, y, rt<<1);
    else if(x > mid)
        qMax(x, y, rt<<1|1);
    else
    {
        qMax(x, mid, rt<<1);
        qMax(mid+1, y, rt<<1|1);
    }
}

void qMin(int x, int y, int rt)
{
    if(tree[rt].l == x && tree[rt].r == y)
    {
        ans2 = min(ans2, tree[rt].Min);
        return ;
    }
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(y <= mid)
        qMin(x, y, rt<<1);
    else if(x > mid)
        qMin(x, y, rt<<1|1);
    else
    {
        qMin(x, mid, rt<<1);
        qMin(mid+1, y, rt<<1|1);
    }
}

int main()
{
    int n, m;
    int x, y;
    while(~scanf("%d%d",&n,&m))
    {
        build(1, n, 1);
        while(m--)
        {
            ans1 = 0;
            ans2 = INF;
            scanf("%d%d",&x,&y);
            qMax(x, y, 1);
            qMin(x, y, 1);
            printf("%d\n",ans1-ans2);
        }
    }
    return 0;
}

H - Can you answer these queries?

HDU - 4027                    

区间更新及求和。
由于对数据开方后区间和没法与更新前的区间和建立递推关系,所以无法和C题一样处理数据。
不过最大的数(2^63)开7次方后也会变成1,所以我们每次直接更新到叶子结点,然后把叶子结点都已无法更新的根节点及叶子结点都标记一下,下次更新时略过就好了。

AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 100010;
struct node
{
    int l, r;
    long long sum;
    bool flag;
} tree[MAX<<2];

void pushup(int rt)
{
    tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
    tree[rt].flag = tree[rt<<1].flag & tree[rt<<1|1].flag; //叶子结点是否已都更新到无法更新
}

void build(int l, int r, int rt)
{
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].sum = tree[rt].flag = 0;
    if(l == r)
    {
        scanf("%lld",&tree[rt].sum);
        if(tree[rt].sum <= 1) tree[rt].flag = 1;
        return ;
    }
    int mid = (l+r)>>1;
    //递归建树
    build(l, mid, rt<<1);
    build(mid+1, r, rt<<1|1);
    pushup(rt);
}

void update(int x, int y, int rt)
{
    if(tree[rt].flag) return ;  //这是一步是关键,省下了很多无用的操作
    //更新这个区间的值
    if(tree[rt].l == tree[rt].r)
    {
        tree[rt].sum = (long long)sqrt(tree[rt].sum*1.0);
        if(tree[rt].sum <= 1) tree[rt].flag = 1;
        return ;
    }
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(y <= mid)
        update(x, y, rt<<1);
    else if(x > mid)
        update(x, y, rt<<1|1);
    else
    {
        update(x, mid, rt<<1);
        update(mid+1, y, rt<<1|1);
    }
    pushup(rt);
}

long long query(int x, int y, int rt)
{
    if(tree[rt].l == x && tree[rt].r == y)
    {
        return tree[rt].sum;
    }
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(y <= mid)
        return query(x, y, rt<<1);
    else if(x > mid)
        return query(x, y, rt<<1|1);
    else
        return query(x, mid, rt<<1) + query(mid+1, y, rt<<1|1);
}

int main()
{
    int n, m;
    int q, x, y;
    int cou = 0;
    while(~scanf("%d",&n))
    {
        printf("Case #%d:\n",++cou);
        build(1, n, 1);
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d%d%d",&q,&x,&y);
            if(x > y) swap(x, y);
            if(q == 1)
            {
                cout << query(x, y, 1) << endl;
            }
            else
            {
                update(x, y, 1);
            }
        }
        puts("");
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值