Description
Data Constraint
Solution
我们发现两个显而易见(一点都不显然好吗)的结论:
1、是否优先不论,我们发现一条u->v的路径可以拆分成u->lca,lca->v两条路径,反之也成立。
2、a->b和c->d等价于a->d和c->b
于是我们得到推论:一个点要么作为起点要么作为终点。(吼啊啊啊)
那么我们就可以很开心的做dp了,由于叶子节点必须靠父亲边才能往上走,所以我们从叶子做起。设f(i)表示i在满足除i以外的以i为根的子树所有的点权值后i的权值,那么若f(i)≠a[i]这锅肯定要靠i与i的父亲的那条边来背,所以f(fa[i])+=a[i]-f(i),表示以i为根的子树要有多少条边经过i的父亲边。同时我们将数量加入i,fa[i]的出入边中。最后统计一下每个点是出边多还是入边多,将它放至边较多的一方。由于结论2,我们可以分别将作为起点和终点的点按大小排序,最后从小往大的匹配即可。
Code
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=2e6+5;
struct code{
int x,sum;
}b[maxn],c[maxn];
int f[maxn],g[maxn],a[maxn],first[maxn],last[maxn],next[maxn],v[maxn],bz[maxn],fa[maxn];
int n,m,i,t,j,k,l,x,y,z,num,num1;
char ch;
int get(){
char ch=getchar();int x=0,z=1;
if (ch=='-') z=-1,ch=getchar();
while (ch>=48 && ch<=57) x=x*10+ch-48,ch=getchar();
return x*z;
}
void lian(int x,int y){
last[++num]=y;next[num]=first[x];first[x]=num;
}
void bfs(){
int i=0,j=1;v[1]=1;
while (i<j){
x=v[++i];bz[x]=1;
for (t=first[x];t;t=next[t])
if (!bz[last[t]])v[++j]=last[t],fa[v[j]]=x;
}
}
bool cmp(code x,code y){
return x.x<y.x;
}
void put(int x){
if (x<10){
ch=x+48;
putchar(ch);return;
}
put(x/10);ch=x%10+48;putchar(ch);
}
int main(){
// freopen("data.in","r",stdin);freopen("data.out","w",stdout);
scanf("%d\n",&n);
for (i=1;i<=n;i++)a[i]=get();
for (i=1;i<n;i++)x=get(),y=get(),lian(x,y),lian(y,x);
bfs();num=num1=0;
for (i=n;i>=1;i--){
x=v[i];t=0;
for (t=first[x];t;t=next[t]){
if (last[t]==fa[x]) continue;
f[x]+=a[last[t]]-f[last[t]];
if (last[t]>x) z=1;
else z=-1;
g[last[t]]+=z*(a[last[t]]-f[last[t]]);
g[x]+=-z*(a[last[t]]-f[last[t]]);
}
}t=0;
memset(bz,0,sizeof(bz));
for (i=1;i<=n;i++)
if (g[i]>0) t+=g[i],bz[i]=1;
for (i=1;i<=n;i++)
if (bz[i]) b[++num].x=i,b[num].sum=g[i],bz[i]=0;
for (i=1;i<=n;i++)
if (g[i]<0) bz[i]=1;
for (i=1;i<=n;i++)
if (bz[i]) c[++num1].x=i,c[num1].sum=-g[i];
k=1;
printf("%d\n",t);
for (i=1;i<=num1;i++){
for (j=1;j<=c[i].sum;j++){
//printf("%d %d\n",c[i].x,b[k].x);
put(c[i].x);putchar(' ');put(b[k].x);putchar('\n');
b[k].sum--;
if (!b[k].sum)k++;
}
}
}