[题解]CF1043E

CF1043E题解

CF1043题解合集

Markdonw源代码

好像其他题解说得都不太清楚???

Update 21.11.17 更正博客地址

题意简述

共有 \(n\) 个人,第 \(i\) 个人有两个属性 \(A_i,B_j\)

其中如果两个人 \(i,j\) 合作,价值为 \(\min(A_i+B_j,A_j+B_i)\)

还有 \(m\) 对关系,其中第 \(i\) 对关系 \(u_i,v_i\) 表示 \(u_i,v_i\) 都不想且不会与对方合作。

让你求的是每一个人与剩余可合作人的合作价值之和。

思路

设想有两个人 \(i,j\)

如果他们的合作价值为 \(A_i+B_j\)

那么需要满足 \(A_i+B_j<A_j+B_i\)

移项得到 \(A_i-B_i<A_j-B_j\)

那么当满足 \(A_i-B_i<A_j-B_j\) 时, \(i\)\((i,j)\) 合作价值的贡献是 \(A_i\) ,否则为 \(B_i\)

所以我们以 \(A_i-B_i\) 为比较条件将所有数据排序,

对于排序后第 \(i\) 个位置的数,

\(Ans_i=\sum\limits_{j=1}^{i-1}(A_j + B_i) = \sum\limits_{j=1}^{i-1}A_j + (n - 1) \times B_i\)

(因为根据上述推导,对于前 \(i - 1\) 个数统称为 \(j\)\(i\) 满足 \(A_i-B_i>A_j-B_j\)

所以 \(i\) 的贡献为 \(B_i\)\(j\) 的贡献为 \(A_j\)

但是第 \(i\) 个数也会与后 \((n-i)\) 个数合作,

所以同理:

\(Ans_i=Ans_i+\sum\limits_{j=i+1}^n(A_i + B_j)=Ans_i+\sum\limits_{j=i+1}^nB_j+(n -i)\times A_i\)

整理后:

\(Ans_i=\sum\limits_{j=1}^{i-1}A_j + (n - 1) \times B_i + \sum\limits_{j=i+1}^nB_j+(n -i)\times A_i\)

\(\,\,\,\,\,\,\,\,\,\,\,\,\,\, = \sum\limits_{j=1}^{i-1}A_j + \sum\limits_{j=i+1}^nB_j+ (n - 1) \times B_i+(n -i)\times A_i\)

\(\sum\limits_{j=1}^{i-1}A_j\)\(\sum\limits_{j=i+1}^nB_j\) 显然不能暴力求出来,

所以加一个对于 \(A\) 的前缀和和对于 \(B\) 的后缀和优化即可。

那么如何处理不合作的情况呢?

我们可以暴力处理每一个人的排斥情况,因为 \(1\le n,m\le 3e5\) ,暴力处理的总共复杂度也只有 \(O(n+m)\)

对于每一个人 \(i\) ,遍历所有与之不合作的人 \(j\)\(Ans_i\) 减去 \(\min(A_i+B_j,A_j+B_i)\)

Code

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 300005;

int n,m;
int sum1[maxn],sum2[maxn];
struct node{int x,y,id;}a[maxn];
vector <int> G[maxn];
int ans[maxn];
map <int,int> rnk;

bool cmp(node a,node b)
{return (a.x - a.y) < (b.x - b.y);}

signed main()
{
    cin >> n >> m;
    for(int i = 1;i <= n;i++)
        scanf("%lld%lld",&a[i].x,&a[i].y),a[i].id = i;
    for(int i = 1;i <= m;i++)
    {
        int u,v;
        scanf("%lld%lld",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    sort(a + 1,a + n + 1,cmp);
    for(int i = 1;i <= n;i++)
        rnk[a[i].id] = i;
    for(int i = 1;i <= n;i++)
        sum1[i] = sum1[i - 1] + a[i].x;
    for(int i = n;i >= 1;i--)
        sum2[i] = sum2[i + 1] + a[i].y;
    for(int i = 1;i <= n;i++)
    {
        ans[a[i].id] += sum1[i - 1] + (i - 1) * a[i].y;
        ans[a[i].id] += sum2[i + 1] + (n - i) * a[i].x;
        for(int k = 0;k < G[a[i].id].size();k++)
        {
            int v = rnk[G[a[i].id][k]];
            ans[a[i].id] -= min(a[i].x + a[v].y,a[i].y + a[v].x);
        }
    }
    for(int i = 1;i <= n;i++)
        cout << ans[i] << " ";
    return 0;
}
posted @ 2021-12-17 18:24  白鹭·笙歌  阅读(47)  评论(0)    收藏  举报