CF1399E2 Weights Division (hard version) 題解
阿新 • • 發佈:2022-05-28
對於兩種權值的分別貪心維護,最後列舉一種權值選多少個,另一個二分出來,總複雜度 \(2\log\)。
點選檢視程式碼
#include<cstdio> #include<iostream> #include<queue> typedef long long ll; inline int min(const int &a,const int &b){return a<b?a:b;} const int N=1e5+13,M=4e6+13,INF=0x3f3f3f3f; struct Edge{int v,w,c,nxt;}e[N<<1]; int n,h[N],tot,siz[N],val[N],cost[N]; ll S,a1[M],a2[M]; struct Node{ int x; Node(int xx=0){x=xx;} bool operator <(const Node &a)const{return ((ll)val[x]+1)/2*siz[x]<((ll)val[a.x]+1)/2*siz[a.x];} }; std::priority_queue<Node> t1,t2; inline void add_edge(int u,int v,int w,int c){e[++tot]=(Edge){v,w,c,h[u]};h[u]=tot;} void dfs(int u,int fa){ bool son=0; for(int i=h[u];i;i=e[i].nxt){ int v=e[i].v;if(v==fa) continue; val[v]=e[i].w,cost[v]=e[i].c; dfs(v,u);siz[u]+=siz[v],son=1; } if(!son) siz[u]=1; } int main(){int T;scanf("%d",&T);while(T--){ scanf("%d%lld",&n,&S); for(int i=1;i<=n;++i) h[i]=siz[i]=0;tot=0; for(int i=1;i<n;++i){ int u,v,w,c;scanf("%d%d%d%d",&u,&v,&w,&c); add_edge(u,v,w,c),add_edge(v,u,w,c); } dfs(1,0);ll Sum=0; for(int i=2;i<=n;++i){ Sum+=(ll)val[i]*siz[i]; if(cost[i]==1) t1.push(Node(i)); else t2.push(Node(i)); } int cnt1=0,cnt2=0; while(!t1.empty()){ int u=t1.top().x;t1.pop(); a1[++cnt1]=a1[cnt1-1]+((ll)val[u]+1)/2*siz[u]; val[u]>>=1; if(val[u]) t1.push(Node(u)); } while(!t2.empty()){ int u=t2.top().x;t2.pop(); a2[++cnt2]=a2[cnt2-1]+((ll)val[u]+1)/2*siz[u]; val[u]>>=1; if(val[u]) t2.push(Node(u)); } int ans=INF; for(int i=0;i<=cnt1;++i){ if(Sum-a1[i]<=S){ans=min(ans,i);break;} if(Sum-a1[i]-a2[cnt2]>S) continue; int l=0,r=cnt2; while(l<r){ int mid=(l+r)>>1; if(Sum-a1[i]-a2[mid]<=S) r=mid; else l=mid+1; } ans=min(ans,i+2*l); } printf("%d\n",ans); } return 0; }