FJUT3574 HOME_W的附加题(带权线段树)题解

Posted kirinsb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FJUT3574 HOME_W的附加题(带权线段树)题解相关的知识,希望对你有一定的参考价值。

题意:

给定n个数a1,a2,a3,……an。和m次操作。

每次操作格式如下

x y k   表示将a[x]替换为y。并求替换后,前k小的数之和

思路:我们用带权线段树维护权值,这里就是维护i的个数num[i],然后顺便维护一下和。每次查询前k个数求和。

练习赛题解:

技术分享图片

 

代码:

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long ll;
const int maxn = 100000 + 10;
const int seed = 131;
const ll MOD = 1e9 + 7;
const ll INF = 1e17;
using namespace std;
int num[maxn << 2], a[maxn], b[maxn];
ll sum[maxn << 2];
void build(int l, int r, int rt){
    if(l == r){
        num[rt] = a[l];
        sum[rt] = l * num[rt];
        return;
    }
    int m = (l + r) >> 1;
    build(l, m, rt << 1);
    build(m + 1, r, rt << 1 | 1);
    num[rt] = num[rt << 1] + num[rt << 1 | 1];
    sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void update(int pos, int l, int r, int rt, int v){
    if(l == r){
        num[rt] += v;
        sum[rt] = l * num[rt];
        return;
    }
    int m = (l + r) >> 1;
    if(pos <= m)
        update(pos, l, m, rt << 1, v);
    else
        update(pos, m + 1, r, rt << 1 | 1, v);
    num[rt] = num[rt << 1] + num[rt << 1 | 1];
    sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
ll query(int l, int r, int rt, int k){
    if(l == r){
        return l * k;
    }
    int m = (l + r) >> 1;
    ll ans = 0;
    if(num[rt << 1] >= k){
        ans += query(l, m, rt << 1, k);
    }
    else{
        ans += sum[rt << 1];
        ans += query(m + 1, r, rt << 1 | 1, k - num[rt << 1]);
    }
    return ans;
}
int main(){
    int n, m;
    memset(a, 0, sizeof(a));
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++){
        scanf("%d", &b[i]);
        a[b[i]]++;
    }
    build(1, 100000, 1);
    int x, y, k;
    for(int i = 0; i < m; i++){
        scanf("%d%d%d", &x, &y, &k);
        update(b[x], 1, 100000, 1, -1);
        update(y, 1, 100000, 1, 1);
        b[x] = y;
        printf("%lld
", query(1, 100000, 1, k));
    }
    return 0;
}

 

以上是关于FJUT3574 HOME_W的附加题(带权线段树)题解的主要内容,如果未能解决你的问题,请参考以下文章

Home_W的难题4(主席树)

Codeforces 666E Forensic Examination SAM+权值线段树

[luogu3767]膜法

POJ2985 并查集+线段树 求第k大的数

[bzoj2733]永无乡&&[bzoj3545]Peaks

树形DP水题系列:FAR-FarmCraft [POI2014][luogu P3574]