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

来源:互联网 发布:数据统计的方法有哪些 编辑:程序博客网 时间:2024/05/10 10:53

题目链接:点击打开链接

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