线段树单点更新

单点更新:最基础的线段树,只更新叶子结点,然后用PushUp函数将信息更新上来。

HDU1166 敌兵布阵

线段树功能:update单点增减,query区间求和。

#include<bits/stdc++.h>

using namespace std;

#define lson l, mid, root << 1
#define rson mid + 1, r, root << 1 | 1
const int maxn = 50005;
int sum[maxn << 2];
int t,n;
char op[10];

void PushUp(int root){
    sum[root] = sum[root << 1] + sum[root << 1 | 1];
}
void build(int l,int r,int root)
{
    if(l == r){
        scanf("%d",&sum[root]);
        return;
    }
    int mid = (l + r) >> 1;
    build(lson);build(rson);
    PushUp(root);
}
void update(int pos,int add,int l,int r,int root)
{
    if(l == r){
        sum[root] += add;
        return;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) update(pos,add,lson);
    else update(pos,add,rson);
    PushUp(root);
}
int query(int L,int R,int l,int r,int root)
{
    if(L <= l && r <= R){
        return sum[root];
    }
    int mid = (l + r) >> 1;
    int ret = 0;
    if(L <= mid) ret += query(L,R,lson);
    if(R > mid) ret += query(L,R,rson);
    return ret;
}
int main()
{
    scanf("%d",&t);
    for(int cas = 1; cas <= t; cas++)
    {
        scanf("%d",&n);
        build(1,n,1);
        printf("Case %d:
",cas);
        while(~scanf("%s",op))
        {
            if(op[0] == 'E') break;
            int a,b;
            scanf("%d%d",&a,&b);
            if(op[0] == 'Q'){
                printf("%d
",query(a,b,1,n,1));
            }
            else if(op[0] == 'S'){
                update(a,-b,1,n,1);
            }
            else{
                update(a,b,1,n,1);
            }
        }
    }
    return 0;
}
View Code

HDU1754 I Hate It

线段树功能:update单点替换,query区间最值。

#include<bits/stdc++.h>

using namespace std;

#define lson l, mid, root << 1
#define rson mid + 1, r, root << 1 | 1
const int maxn = 200005;
int MAX[maxn << 2];
int n,m,a,b;
char op[5];

void PushUp(int root){
    MAX[root] = max(MAX[root <<1],MAX[root << 1 | 1]);
}
void build(int l,int r,int root)
{
    if(l == r){
        scanf("%d",&MAX[root]);
        return;
    }
    int mid = (l + r) >> 1;
    build(lson);build(rson);
    PushUp(root);
}
void update(int pos,int src,int l,int r,int root)
{
    if(l == r){
        MAX[root] = src;
        return;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) update(pos,src,lson);
    else update(pos,src,rson);
    PushUp(root);
}
int query(int L,int R,int l,int r,int root)
{
    if(L <= l && r <= R){
        return MAX[root];
    }
    int mid = (l + r) >> 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;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        build(1,n,1);
        while(m--)
        {
            scanf("%s%d%d",op,&a,&b);
            if(op[0] == 'Q'){
                printf("%d
",query(a,b,1,n,1));
            }
            else{
                update(a,b,1,n,1);
            }
        }
    }
    return 0;
}
View Code

HDU1394 Minimum Inversion Number

题意:一个由0...n-1组成的序列,每次将队首的元素移到队尾,求形成的n个序列中最小逆序对数目。

思路:O(nlogn)复杂度求出最初的逆序对数后,O(1)地推出其他序列的逆序对数。

线段树功能:update单点增减,query区间求和。

#include<bits/stdc++.h>

using namespace std;

#define lson l, mid, root << 1
#define rson mid + 1, r, root << 1 | 1
const int maxn = 5005;
int sum[maxn << 2],x[maxn];
int n,ans,res;

void PushUp(int root){
    sum[root] = sum[root << 1] + sum[root << 1 | 1];
}
void build(int l,int r,int root)
{
    sum[root] = 0;
    if(l == r)return;
    int mid = (l + r) >> 1;
    build(lson);build(rson);
}
void update(int pos,int l,int r,int root)
{
    if(l == r){
        sum[root]++;
        return;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) update(pos,lson);
    else update(pos,rson);
    PushUp(root);
}
int query(int L,int R,int l,int r,int root)
{
    if(L <= l && r <= R){
        return sum[root];
    }
    int mid = (l + r) >> 1;
    int ret = 0;
    if(L <= mid) ret += query(L,R,lson);
    if(R >= mid) ret += query(L,R,rson);
    return ret;
}
int main()
{
    while(~scanf("%d",&n))
    {
        build(0,n-1,1);
        ans = 0;
        for(int i=0;i<n;i++){
            scanf("%d",&x[i]);
            ans += query(x[i],n-1,0,n-1,1);
            update(x[i],0,n-1,1);
        }
        res = ans;
        for(int i=0;i<n;i++){
            ans += n - x[i] - x[i] - 1;
            res = min(res,ans);
        }
        printf("%d
",res);
    }
    return 0;
}
View Code

 HDU2795 Billboard

题意:h*w的木板,放进一些1*L的物品,求每次放空间能容纳且最上边的位子。

思路:求区间最大值,每次找到最大值的位置然后减去L。实际上就是不断的二分区间寻找合法的位置。

线段树功能:query区间最大值的位置,update的操作放在了query里面做。

#include<bits/stdc++.h>

using namespace std;

#define lson l, mid, root << 1
#define rson mid + 1, r, root << 1 | 1
const int maxn = 200005;
int h,w,n;
int MAX[maxn << 2];

void PushUp(int root){
    MAX[root] = max(MAX[root << 1],MAX[root << 1 | 1]);
}
void build(int l,int r,int root)
{
    MAX[root] = w;
    if(l == r) return;
    int mid = (l + r) >> 1;
    build(lson);build(rson);
}
int query(int x,int l,int r,int root)
{
    if(l == r){
        MAX[root] -= x;
        return l;
    }
    int mid = (l + r) >> 1;
    int ret = MAX[root << 1] >= x ? query(x,lson) : query(x,rson);
    PushUp(root);
    return ret;
}
int main()
{
    while(~scanf("%d%d%d",&h,&w,&n))
    {
        if(h > n) h = n;
        build(1,h,1);
        while(n--)
        {
            int x;scanf("%d",&x);
            if(MAX[1] < x) puts("-1");
            else printf("%d
",query(x,1,h,1));
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/solvit/p/9559527.html