CF1399E2 Weights Division (hard version)

The difference from E1 lies in the cost of operating on different edges, which can be 1 and 2.
If you follow the similar method of E1 , it seems to be very troublesome and requires several stacks to maintain.
Let’s first consider how the final answer came about.
Obviously, a operation is performed on an edge whose operation cost is 1 once, and an operation is performed on an edge whose operation cost is 2 times. And we don't know a and b. But it is certain that this a time must be performed on the edge that contributes the most to each operation, and the same is true for the b time.
Then we can think of dividing the edge that costs 1 and the edge that costs 2 into two parts. We enumerate how many times an edge cost 1 should be operated on, and then perform operations on an edge cost 2 for a single operation, and get the answer in two points. At a glance, the time complexity is: O(n log n). (Because the number of edges is n)
Then it is found that since w[i]<=1e16, each edge will be operated at most 54 times, so there are at most 5.4 million edges, O(54n log 54n), which is OK.
If when writing E1, instead of using the heap to process it, but directly thinking of processing the several edges generated after deleting each edge several times, put them together, and then directly O(n) sweep back after sorting, then it will Greatly shorten the code implementation time of these two questions.
Akiko Hime Koji is still strong! ! !
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int T,n,s,aa,bb,sum,l,r,mid,hh,ans;
int d[N],size[N],a[54*N],b[54*N];
struct number{
    
    int x,y,w,opt;}num[N];
int cnt,head[N];
struct edge{
    
    int next,to,w;}e[N<<1];

inline void add(int u,int v,int w)
{
    
    
	cnt++;
	e[cnt].next=head[u];
	e[cnt].to=v;
	e[cnt].w=w;
	head[u]=cnt;
}

void dfs(int u,int fa)
{
    
    
	bool jay=true;
	for (register int i=head[u]; i; i=e[i].next)
	if (e[i].to!=fa)
	{
    
    
		jay=false;
		d[e[i].to]=d[u]+1;
		dfs(e[i].to,u);
		size[u]+=size[e[i].to];
	}
	if (jay) size[u]=1; 
}

signed main(){
    
    
	scanf("%lld",&T);
	while (T--)
	{
    
    
		scanf("%lld%lld",&n,&s);
		cnt=0;
		for (register int i=1; i<=n; ++i) head[i]=0;
		d[1]=0;
		for (register int i=1; i<=n; ++i) size[i]=0;
		for (register int i=1; i<n; ++i)
		{
    
    
			scanf("%lld%lld%lld%lld",&num[i].x,&num[i].y,&num[i].w,&num[i].opt);
			add(num[i].x,num[i].y,num[i].w);
			add(num[i].y,num[i].x,num[i].w);	
		}
		dfs(1,0);
		aa=bb=0;
		sum=0;
		for (register int i=1; i<n; ++i)
		{
    
    
			if (d[num[i].x]>d[num[i].y]) swap(num[i].x,num[i].y);
			sum+=size[num[i].y]*num[i].w;
			if (num[i].opt==1)
			{
    
    
				while (num[i].w)
				{
    
    
					int del=num[i].w-num[i].w/2;
					a[++aa]=del*size[num[i].y];
					num[i].w/=2;
				}
			}
			else
			{
    
    
				while (num[i].w)
				{
    
    
					int del=num[i].w-num[i].w/2;
					b[++bb]=del*size[num[i].y];
					num[i].w/=2;
				}
			}
		}
		sort(a+1,a+aa+1); reverse(a+1,a+aa+1);
		sort(b+1,b+bb+1); reverse(b+1,b+bb+1);
		for (register int i=1; i<=aa; ++i) a[i]+=a[i-1];
		for (register int i=1; i<=bb; ++i) b[i]+=b[i-1];
		ans=1e18;
		for (register int i=0; i<=aa; ++i)
		{
    
    
			l=0; r=bb; hh=-1;
			while (l<=r)
			{
    
    
				mid=l+r>>1;
				if (sum-(a[i]+b[mid])<=s) hh=mid,r=mid-1;
				else l=mid+1;	
			}
			if (~hh) ans=min(ans,i+hh*2);
		}
		printf("%lld\n",ans);
	}
return 0;
}

Guess you like

Origin blog.csdn.net/Dove_xyh/article/details/108434415