CF1363E 题解

CF1363E 题解

$\text{Description}$

给定一棵以 $1$ 为根的有根树,每个节点有三个权值 $a_i,b_i,c_i$。每次操作可以选定一个节点 $x$,然后选择其子树内任意个节点(设为 $k$ 个)并任意排列其 $b_i$,花费 $k\times a_i$。你可以进行若干次操作,求使得所有结点的 $b_i=c_i$ 的最小花费。

$\text{Solution}$

对于一个节点,对其祖先进行操作是完全包含对这个节点进行操作的所有功能的。所以,只要该节点存在一个祖先节点满足其权值小于该节点的权值,那么我们就不管这个节点。

所以,一个节点被操作,要尽量选取其祖先节点中花费最小的节点,我们按照这个规则重新赋权,然后自底向下尽量匹配即可。

$\text{Code}$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include<bits/stdc++.h>
#define REG register
using namespace std;
inline void read(int& x){
static char c;
while(!isdigit(c=getchar()));x=c^48;
while(isdigit(c=getchar()))x=(x*10)+(c^48);
}

const int M=200005;

int n,A[M],B[M],C[M],S1,S2;

int MA[M],SB[M],SC[M];

long long ans;

struct Edge{int v,nxt;}ed[M<<1];
int head[M],cnt;
inline void adde(int u,int v){ed[++cnt]=(Edge){v,head[u]},head[u]=cnt;}
inline void add(int u,int v){adde(u,v),adde(v,u);}
#define FORE(i,Now) for(REG int i=head[Now];i;i=ed[i].nxt)

void dfs(int Now,int Fa){
MA[Now]=min(MA[Fa],A[Now]);
FORE(i,Now){
int v=ed[i].v;
if(v==Fa) continue;
dfs(v,Now);
SB[Now]+=SB[v],SC[Now]+=SC[v];
}
SB[Now]+=(B[Now]^C[Now])&B[Now],SC[Now]+=(B[Now]^C[Now])&(!B[Now]);
if(A[Now]>MA[Fa]) return;
ans+=2ll*A[Now]*min(SB[Now],SC[Now]);
SB[Now]-=min(SB[Now],SC[Now]),SC[Now]-=min(SB[Now],SC[Now]);
}

int u,v;

inline void Work(){
read(n),MA[1]=1000000005;
for(REG int i=1;i<=n;++i) read(A[i]),read(B[i]),read(C[i]);
for(REG int i=1;i<=n;++i)
if(B[i]^C[i]) B[i]?++S1:++S2;
if(S1^S2){puts("-1");return;}
for(REG int i=1;i<n;++i)
read(u),read(v),add(u,v);
dfs(1,1);
printf("%lld\n",ans);
}

int main(){Work();}
#
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×