https://codeforces.com/problemset/problem/1363/E
这题一看到子树,立刻想到dfs序,然后直接dfs序搞线段树打区间标记,bit维护区间剩余换0的个数和换1的个数,然后把点按ai排序搞就行了。因为一个cost更小的点,肯定是它能处理的尽量处理,然后如果当前这个枚举的点被某个ai更小点曾经处理过这个dfs序的区间了,说明那个ai更小的点是它的父节点,他就什么都不能干。这个点把他能处理的处理完之后,在dfn[id]的位置减去处理的个数,01都减,因为如果之后他的某个父节点要求值时,dfs序的区间会包括他的区间,dfn[id]这个位置肯定包含其中,那么就能求出当前这个点最多能处理多少点了。
然后写了一个小时wa了。。。
在查错的时候,发现我只要考虑每个不同的点被哪个祖先点给处理就行了。。。于是直接dfs向下,维护当前点和所有祖先点的最小值val,然后当前子树剩余的要换的0和要换的1取个最小值,就是要处理的点,用val乘他们就行了。。。这个写法10分钟就写完了。。。还好最后过了,不然能气死
还是太菜了,应该想更简单的办法的,不应该冲动
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
int n,m,cas,k,ind,sum1,sum2;
int b[maxl],c[maxl],dfn[maxl],out[maxl];
int q[2][maxl];
char s[maxl];
bool in[maxl],vis[maxl];
vector<int> e[maxl];
struct node
{
int l,r,tag;
}tree[maxl*4];
ll bit[2][maxl],sum[2][maxl];
ll ans;
struct tn
{
int id,val;
}a[maxl];
inline void dfs(int u,int fa,int val)
{
vis[u]=true;dfn[u]=++ind;
if(b[u]!=c[u])
{
q[c[u]][u]++;sum[c[u]][u]=1;
}
ll mi,now,tot=0;
for(int v:e[u])
{
if(v==fa) continue;
dfs(v,u,min(val,a[v].val));
sum[0][u]+=sum[0][v];
sum[1][u]+=sum[1][v];
}
mi=min(sum[0][u],sum[1][u]);
sum[0][u]-=mi;sum[1][u]-=mi;
ans+=mi*val*2;
}
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&a[i].val,&b[i],&c[i]);
a[i].id=i;
}
int u,v;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
ans=0;
dfs(1,0,a[1].val);
for(int i=1;i<=n;i++)
{
if(q[0][i])
sum1++;
if(q[1][i])
sum2++;
}
if(sum1!=sum2)
ans=-1;
}
inline void mainwork()
{
}
inline void print()
{
printf("%lld\n",ans);
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
int n,m,cas,k,ind,sum1,sum2;
int b[maxl],c[maxl],dfn[maxl],out[maxl];
int q[2][maxl];
char s[maxl];
bool in[maxl],vis[maxl];
vector<int> e[maxl];
struct node
{
int l,r,tag;
}tree[maxl*4];
ll bit[2][maxl];
ll ans;
struct tn
{
int id,val;
}a[maxl];
inline void dfs(int u,int fa)
{
vis[u]=true;dfn[u]=++ind;
if(b[u]!=c[u])
q[c[u]][u]++;
ll mi,now,tot=0;
for(int v:e[u])
{
if(v==fa) continue;
dfs(v,u);
}
out[u]=ind;
}
inline void add(int i,int x,int id)
{
while(i<=n)
{
bit[id][i]+=x;
i+=i&-i;
}
}
inline ll sum(int i,int id)
{
ll ret=0;
while(i)
{
ret+=bit[id][i];
i-=i&-i;
}
return ret;
}
inline void build(int k,int l,int r)
{
tree[k].l=l;tree[k].r=r;
if(l==r)
{
tree[k].tag=0;
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&a[i].val,&b[i],&c[i]);
a[i].id=i;
}
int u,v;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1,0);
build(1,1,n);
sum1=0,sum2=0;
for(int i=1;i<=n;i++)
{
if(q[0][i])
add(dfn[i],1,0),sum1++;
if(q[1][i])
add(dfn[i],1,1),sum2++;
}
}
inline void upd(int k,int l,int r)
{
if(tree[k].l==l && tree[k].r==r)
{
tree[k].tag=1;
return;
}
int mid=(tree[k].l+tree[k].r)>>1;
if(r<=mid)
upd(k<<1,l,r);
else if(l>mid)
upd(k<<1|1,l,r);
else
{
upd(k<<1,l,mid);
upd(k<<1|1,mid+1,r);
}
}
inline bool qry(int k,int l)
{
if(tree[k].l==tree[k].r)
return tree[k].tag;
if(tree[k].tag) return true;
int mid=(tree[k].l+tree[k].r)>>1;
if(l<=mid)
return qry(k<<1,l);
else
return qry(k<<1|1,l);
}
inline bool cmp(const tn &x,const tn &y)
{
return x.val<y.val;
}
inline void mainwork()
{
if(sum1!=sum2)
{
ans=-1;
return;
}
sort(a+1,a+1+n,cmp);
ll t0,t1,d,id;
for(int i=1;i<=n;i++)
{
id=a[i].id;
if(qry(1,dfn[id])) continue;
t0=sum(out[id],0)-sum(dfn[id]-1,0);
t1=sum(out[id],1)-sum(dfn[id]-1,1);
d=min(t1,t0);
add(dfn[id],-d,0);
add(dfn[id],-d,1);
upd(1,dfn[id],out[id]);
ans+=1ll*a[i].val*d*2;
}
}
inline void print()
{
printf("%lld\n",ans);
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}