CF 1051 G. Distinctification

 

G. Distinctification

链接

分析:

  线段树合并 + 并查集。

  最后操作完后a连续递增的一段,b一定是递减的。最后的答案是$\sum (a_{new}-a_{odd}) \times b_i$,即改变后的a减去之前的a。

  那么对于连续的一段考虑怎么求。按照bi建立权值线段树,线段树的一个节点的答案就是 左区间的答案+右区间的答案+左区间的和 × 右区间的个数。

  即最大的$b_i$乘1,次大的乘2,...,最小的乘(n-1)分别是每个$b_i$的排名。这是对b排序后,新的答案,减去以前的即可得到答案。

  如果存在相同的a,那么让a变成a+1,存在a+1,那么变成a+2……加上变后的贡献,并查集维护。注意扩大值域后,开两倍空间。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cctype>
#include<set>
#include<vector>
#include<queue>
#include<map>
#define fi(s) freopen(s,"r",stdin);
#define fo(s) freopen(s,"w",stdout);
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 400005;
int ls[N * 20], rs[N * 20], siz[N * 20], Root[N], R[N], fa[N], Index;
LL sum[N * 20], Ans;

void Insert(int l,int r,int &now,int p) {
    if (!now) now = ++Index;
    if (l == r) { siz[now] = 1, sum[now] = p; return ; }
    int mid = (l + r) >> 1;
    if (p <= mid) Insert(l, mid, ls[now], p);
    else Insert(mid + 1, r, rs[now], p);
    sum[now] = sum[ls[now]] + sum[rs[now]], siz[now] = siz[ls[now]] + siz[rs[now]];
}
int Merge(int x,int y) {
    if (!x || !y) return x | y;
    Ans -= sum[ls[x]] * siz[rs[x]] + sum[ls[y]] * siz[rs[y]];
    ls[x] = Merge(ls[x], ls[y]);
    rs[x] = Merge(rs[x], rs[y]);    
    Ans += sum[ls[x]] * siz[rs[x]], siz[x] += siz[y], sum[x] += sum[y];
    return x;
}
int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
void solve(int x,int y) {
    x = find(x), y = find(y); fa[y] = x;
    Ans -= sum[Root[x]] * x + sum[Root[y]] * y;
    Root[x] = Merge(Root[x], Root[y]);
    Ans += sum[Root[x]] * x;
    R[x] = R[y];
}
int main() {
    int n = read();
    for (int i = 1; i <= 400000; ++i) fa[i] = i, R[i] = i;
    for (int i = 1; i <= n; ++i) {
        int a = read(), b  = read();
        int p = Root[a] ? R[find(a)] + 1 : a;
        Ans -= 1ll * a * b;
        Insert(1, n, Root[p], b);
        Ans += 1ll * p * b;
        if (Root[p - 1]) solve(p - 1, p);
        if (Root[p + 1]) solve(p, p + 1);
        printf("%I64d\n", Ans);
    }    
    return 0;
}

 

posted @ 2019-02-20 15:05  MJT12044  阅读(390)  评论(0编辑  收藏  举报