[题解]CF1043E
CF1043E题解
好像其他题解说得都不太清楚???
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;
}

浙公网安备 33010602011771号