本文共 1593 字,大约阅读时间需要 5 分钟。
每个人做第一题需要 a i a_i ai事件,做第二题需要 b i b_i bi的事件
每个人都要和其他 n − 1 n-1 n−1个人组成一组队伍做一次题,你能选择的就是谁做第一题谁做第二题。
但是现在有 m m m对关系起了冲突,不能组队
求能组队的最小花费时间总和.
n < = 300000 n<=300000 n<=300000
考虑 ( a i , b i ) (a_i,b_i) (ai,bi)和 ( a j , b j ) (a_j,b_j) (aj,bj)
花费是 m i n ( a i + b j , b i + a j ) min(a_i+b_j,b_i+a_j) min(ai+bj,bi+aj)
两种选择方式的费用差是 a i + b j − a j − b i a_i+b_j-a_j-b_i ai+bj−aj−bi
也就是 ( a i − b i ) − ( a j − b j ) (a_i-b_i)-(a_j-b_j) (ai−bi)−(aj−bj)
当 a i − b i > a j − b j a_i-b_i>a_j-b_j ai−bi>aj−bj说明 b i + a j b_i+a_j bi+aj的方式比较好(因为差是正数)
当 a i − b i < a j − b j a_i-b_i<a_j-b_j ai−bi<aj−bj说明 a i + b j a_i+b_j ai+bj的方式比较好(因为差是负数)
那我们按照 a i − b i a_i-b_i ai−bi来排个序
对于第 i i i个人来说
[ 1 , i − 1 ] [1,i-1] [1,i−1]个人由于 a j − b j a_j-b_j aj−bj比较小,所以都是贡献 a j a_j aj出来
[ i + 1 , n ] [i+1,n] [i+1,n]个人由于 a j − b j a_j-b_j aj−bj比较大,所以都是贡献 b j b_j bj说来
如此一来,计算一个 a , b a,b a,b数值的前缀和就可以轻松求解
至于 m m m对关系,直接暴力减去就好了。
#includeusing namespace std;#define int long longconst int maxn = 1e6+10;struct edge{ int a,b,id; bool operator < (const edge&tmp ) const{ return a-b > n >> m; for(int i=1;i<=n;i++) { scanf("%lld%lld",&s[i].a,&s[i].b ); s[i].id = i; } for(int i=1;i<=m;i++) { int l,r; scanf("%lld%lld",&l,&r); ans[l] -= min(s[l].a+s[r].b,s[l].b+s[r].a); ans[r] -= min(s[l].a+s[r].b,s[l].b+s[r].a); } sort( s+1,s+1+n ); for(int i=1;i<=n;i++) { prea[i] = prea[i-1]+s[i].a; preb[i] = preb[i-1]+s[i].b; } for(int i=1;i<=n;i++) { int x = prea[i-1],y = preb[n]-preb[i]; ans[s[i].id] += x+y+(i-1)*s[i].b+(n-i)*s[i].a; } for(int i=1;i<=n;i++) printf("%lld ",ans[i] );}
转载地址:https://issue-is-vegetable.blog.csdn.net/article/details/113625374 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!