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++;
}
}
}