红黑树 - 贪心

给定一棵有根树,根为1,边有边权,点有颜色(红色或黑色)。1号点一定是红色。定义一个红点的价值是0,黑点的价值是它到距离它最近的红色祖先的距离。有m次询问,每次给出k个点,你可以改变树上的最多一个点的颜色(根除外),在此前提下求给出的k个点的权值的最大值最小是多少。注意每次询问是独立的,也就是说你在这次询问中改变一个点的颜色,在下次询问时就会复原。

场上傻了吧唧的写了个虚树二分光荣TLE。
然而可以直接排个序然后贪心即可。

#include<bits/stdc++.h>
#define R(i,a,b) for(_ i=a;i<=b;i++)
#define V return
using namespace std;typedef long long L;typedef int _;const _ N=100010;typedef _ A[N];_ gc(){V getchar();}struct K{_ T,P,W;}e[N];A G,d,S,h,a,T;L tr[N],D[N];_ U[N][20],n,m,x,w,E;_ I(){_ x,c;while((c=gc())<'0'||c>'9');x=c^'0';while((c=gc())>='0'&&c<='9')x=x*10+c-'0';V x;}_ IC(_ x=0){while((x=gc())!='0'&&x!='1');V x^'0';}_ DC(_ x,_ y){V D[x]>D[y];}_ AD(_ u,_ v,_ w){V e[++E].T=v,e[E].P=h[u],e[E].W=w,h[u]=E;}_ O(_ x){R(i,1,G[d[x]])U[x][i]=U[U[x][i-1]][i-1];if(S[x]) D[x]=0,T[x]=x;for(_ i=h[x],y;i;i=e[i].P)U[y=e[i].T][0]=x,d[y]=d[x]+1,T[y]=T[x],D[y]=D[x]+e[i].W,tr[y]=tr[x]+e[i].W,O(y);V 0;}_ getLCA(_ x,_ y){if(d[x]<d[y]) swap(x,y);for(_ i=G[d[x]];i>=0;i--)if(d[U[x][i]]>=d[y])x=U[x][i];if(x==y)V x;for(_ i=G[d[x]];i>=0;i--)if(U[x][i]^U[y][i])x=U[x][i],y=U[y][i];V U[x][0];}_ main(){n=I(),m=I();R(i,2,n)S[i]=!IC();R(i,2,n)x=I(),w=I(),AD(x,i,w),G[i]=G[i>>1]+1;T[1]=S[1]=d[1]=1,O(1);while(m--){_ k=I(),C=0,x;L ans,w1,w2;while(k--)if(!S[x=I()])a[++C]=x;if(C<=1){printf("0\n");continue;}sort(a+1,a+C+1,DC),ans=D[a[2]],a[C+1]=0;for(_ i=2,c=a[1];i<=C;i++){if(T[a[1]]!=T[a[i]]||d[c=getLCA(c,a[i])]<=d[T[a[1]]])break;ans=min(ans,max(w1=D[a[i+1]],w2=tr[a[1]]-tr[c]));if(w1<=w2)break;}printf("%lld\n",ans);}V 0;}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值