一、题目
二、解法
建议多读几遍题,读懂了之后会发现暴力算法是 O ( n 2 ) O(n^2) O(n2)。
考虑选取的条件,假设应该选取
i
i
i做第一道题,
j
j
j做第二道题:
x
i
+
y
j
<
y
i
+
x
j
x_i+y_j<y_i+x_j
xi+yj<yi+xj
x
i
−
y
i
<
x
j
+
y
j
x_i-y_i<x_j+y_j
xi−yi<xj+yj你会发现这样选取的条件就取决于
i
i
i它自身了,我们可以把所有人按
x
−
y
x-y
x−y排序,然后枚举
i
i
i,在
i
i
i之前的让
i
i
i做第二道题,否则
i
i
i做第一道题,这样用一个前缀和就可以统计了,那个
m
m
m对限制直接暴力删去贡献,不是难点。
这应该算是贪心优化统计吧,时间复杂度 O ( n log n ) O(n\log n) O(nlogn),贴个代码。
#include <cstdio>
#include <algorithm>
using namespace std;
#define int long long
const int M = 300005;
int read()
{
int x=0,flag=1;
char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,tot,ans[M],f[M],p1[M],p2[M];
struct edge
{
int v,next;
edge(int V=0,int N=0) : v(V) , next(N) {}
}e[2*M];
struct node
{
int x,y,id;
node(int X=0,int Y=0) : x(X) , y(Y) {}
bool operator < (const node &R) const
{
return x-y<R.x-R.y;
}
}a[M];
signed main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
a[i].x=read(),a[i].y=read(),a[i].id=i;
for(int i=1;i<=m;i++)
{
int u=read(),v=read(),c=min(a[u].x+a[v].y,a[u].y+a[v].x);
e[++tot]=edge(c,f[u]),f[u]=tot;
e[++tot]=edge(c,f[v]),f[v]=tot;
}
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
{
p1[i]=p1[i-1]+a[i].x;
p2[i]=p2[i-1]+a[i].y;
}
for(int i=1;i<=n;i++)
{
int id=a[i].id;
ans[id]=p1[i-1]+p2[n]-p2[i]+(i-1)*a[i].y+(n-i)*a[i].x;
for(int j=f[id];j;j=e[j].next)
ans[id]-=e[j].v;
}
for(int i=1;i<=n;i++)
printf("%lld ",ans[i]);
}