树状数组

单点修改 + 单点查询

楼兰图腾

题目描述
image
image

参考题解

点击跳转

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int N = 2e5+5;

typedef long long LL;

int n;
int a[N];
int treeMessage[N]; //the cnt of i

int ll[N], lg[N], rl[N], rg[N];

int lowbit(int x)
{
    return x & (-x);
}

void add(int x, int v)
{
    for(; x <= n; x += lowbit(x))
    {
        treeMessage[x] += v;
    }
}

// the sum of treeMessage[i], i: 1~x
int query(int x)
{
    int ans = 0;
    while(x > 0)
    {
        ans += treeMessage[x];
        x = x - lowbit(x);
    }
    return ans;
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; ++ i)
    {
        scanf("%d", a+i);
    }
    for(int i = 1; i <= n; i ++)
    {
        ll[i] = query(a[i]-1);
        lg[i] = i-1 - query(a[i]); //之前有i-1个数,不包括a[i]
        add(a[i], 1);
    }
    memset(treeMessage, 0, sizeof treeMessage);
    for(int i = n; i > 0; -- i)
    {
        rl[i] = query(a[i]-1);
        rg[i] = n-i - query(a[i]);
        add(a[i], 1);
    }
    LL ans1 = 0, ans2 = 0;
    for(int i = 1; i <= n; ++ i)
    {
        ans1 += lg[i] * (LL)rg[i];
        ans2 += ll[i] * (LL)rl[i];
    }
    cout << ans1 << " " << ans2 << endl;
    return 0;
}

区间修改 + 单点查询

一个简单的整数问题

题目描述
image
image

参考题解

利用差分转换成 单点修改+区间查询

#include <iostream>
#include <cstdio>

using namespace std;

const int N = 1e5+5;

int n, m;

int d[N]; //差分数组

int tree[N];

int lowbit(int x)  // 返回末尾的1
{
    return x & -x;
}

//单点修改
void add(int x, int v)
{
    for(; x <= n; x+=lowbit(x))
    {
        tree[x] += v;
    }
}

//区间查询1~x
int query(int x)
{
    int ans = 0;
    while(x>0)
    {
        ans += tree[x];
        x -= lowbit(x);
    }
    return ans;
}

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; ++ i)
    {
        scanf("%d", d+i);
    }
    int last = 0;
    for(int i = 1; i <= n; ++ i)
    {
        int tp = d[i];
        d[i] = d[i] - last;
        last = tp;
        add(i, d[i]);
    }
    while (m -- )
    {
        char op[2];
        scanf("%s", op);
        if(op[0] == 'C')
        {
            int l, r, d;
            scanf("%d%d%d", &l, &r, &d);
            add(l, d);
            add(r+1, -d);
        }
        else
        {
            int x;
            scanf("%d", &x);
            cout << query(x) << endl;
        }
    }
    return 0;
}

区间修改 + 区间查询

一个简单的整数问题2

题目描述
image
image

参考题解

利用差分和数学推导改为单点修改和区间查询
链接跳转

#include <iostream>
#include <cstdio>

using namespace std;

const int N = 1e5+5;

typedef long long LL;

int n, m;

int d[N];

LL tree1[N];
LL tree2[N]; //tree1: d, tree2: d*i

int lowbit(int x)
{
    return x&(-x);
}

//下标x处添加v
void add(LL tr[], int x, LL v)
{
    for(; x <= n; x+=lowbit(x))
    {
        tr[x] += v;
    }
}

//返回1~x的sum
LL query(int x)
{
    int tp = x;
    LL sum1 = 0, sum2 = 0;
    while(x > 0)
    {
        sum1 += tree1[x];
        sum2 += tree2[x];
        x -= lowbit(x);
    }
    return sum1*(tp+1) - sum2;
}

int main()
{
    cin >> n >> m;
    int last = 0;
    for(int i = 1; i <= n; ++ i)
    {
        scanf("%d", d+i);
        int tp = d[i];
        d[i] = d[i] - last;
        last = tp;
        add(tree1, i, d[i]);
        add(tree2, i, i*(LL)d[i]);
    }
    // for(int i = 1; i <= n; ++ i)
    // {
    //     cout << query(i)-query(i-1) << endl;
    // }
    while (m -- )
    {
        char op[2];
        int l, r;
        scanf("%s%d%d", op, &l, &r);
        if(op[0] == 'Q')
        {
            printf("%lld\n", query(r)-query(l-1));
        }
        else
        {
            int d;
            scanf("%d", &d);
            add(tree1, l, d);
            add(tree2, l, l*(LL)d);
            add(tree1, r+1, -d);
            add(tree2, r+1, (r+1)*(LL)(-d));
        }
    }
    return 0;
}

用01数组动态维护:删除元素 + 查询数量

谜一样的牛

题目描述
image

参考题解

从最后一头牛开始从右往左逐个推断每头牛是1n中的多少身高,因为1n中的数会因为往前的原因逐个删掉右边已经计算过的元素,所以1n呈现动态删除。采用树状数组维护1n的01数组表示是否被删除,sum(i)就是i前面的i的个数,用二分查询出sum[t]刚好等于a[i]+1的的t(多个的话选最左边的那个),即是其身高。

#include <iostream>
#include <cstdio>

using namespace std;

const int N = 1e5+5;

int n;

int lowerCnt[N];

int tree[N];

int lowbit(int x)
{
    return x & (-x);
}

//在下标x处+v
void add(int x, int v)
{
    for(; x < n; x += lowbit(x))
    {
        tree[x] += v;
    }
}

//1~x的sum
int query(int x)
{
    int res =0;
    while(x > 0)
    {
        res += tree[x];
        x -= lowbit(x);
    }
    return res;
}

bool check(int x, int height)
{
    if(query(x)>=height)
    {
        return true;
    }
    return false;
}

int ans[N];

int main()
{
    cin >> n;
    for(int i = 2; i <= n; ++ i)
    {
        scanf("%d", lowerCnt+i);
    }
    for(int i = 1; i <= n; ++ i)
    {
        add(i, 1);
    }
    for(int i = n; i >= 1; -- i)
    {
        int height = lowerCnt[i] + 1;
        //查询sum>=height的最小值
        int l = 1, r = n;
        while(l < r)
        {
            int mid = l+r>>1;
            if(check(mid, height))
            {
                r = mid;
            }
            else
            {
                l = mid+1;
            }
        }
        ans[i] = l;
        add(l, -1);
    }
    for(int i = 1; i <= n; ++ i)
    {
        printf("%d\n", ans[i]);
    }
    return 0;
}
posted @ 2021-05-12 17:42  chaosliang  阅读(48)  评论(0)    收藏  举报