• CF 1051 G. Distinctification


    G. Distinctification

    链接

    分析:

      线段树合并 + 并查集。

      最后操作完后a连续递增的一段,b一定是递减的。最后的答案是$sum (a_{new}-a_{odd}) imes 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
    ", Ans);
        }    
        return 0;
    }
  • 相关阅读:
    poj 2584 T-Shirt Gumbo (二分匹配)
    hdu 1757 A Simple Math Problem (乘法矩阵)
    矩阵之矩阵乘法(转载)
    poj 2239 Selecting Courses (二分匹配)
    hdu 3661 Assignments (贪心)
    hdu 1348 Wall (凸包)
    poj 2060 Taxi Cab Scheme (二分匹配)
    hdu 2202 最大三角形 (凸包)
    hdu 1577 WisKey的眼神 (数学几何)
    poj 1719 Shooting Contest (二分匹配)
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10406703.html
Copyright © 2020-2023  润新知