CF1303G Sum of Prefix Sums

考虑点分治。

考虑如何合并线段 \(\sum\limits_{i=1}^{n}i\times a[i]\)\(\sum\limits_{j=1}^{m}j\times b[j]\)。新线段的表达式 \(\sum\limits_{i=1}^{n}i\times a[i] + \sum\limits_{j=1}^{m}j\times b[j] + n\times \sum\limits_{j=1}^{m}b[j]\)

我们把 \(\sum\limits_{j=1}^{m}b[j]\) (斜率)和 \(\sum\limits_{j=1}^{m}j\times b[j]\)(截距) 当做插入放进李超树中,\(n\) 当做询问就可以解决这道题了。

一些细节还是在处理根的问题上,注意一下就好。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<ctime>
#define int long long
using namespace std;

const int N=150009;
int head[N],cnt,n,p[N],siz[N],del[N],a[N],all,
b[N],len[N],sum[N],_sum[N],Ans,Sum[N],bin[N],X;
struct Edge
{
	int nxt,to;
}g[N*2];
struct LC_Tree
{
	int K[N],B[N],tag[N*4],cnt;
	
	void Insert(int a,int b,int fuck)
	{
		K[++cnt]=a,B[cnt]=b;
		Modify(1,1,fuck,cnt);
	}
	
	int val(int id,int x) { return K[id]*x+B[id]; }
	
	void Modify(int k,int l,int r,int id)
	{
		if(l==r)
		{
			tag[k]=val(id,l)>val(tag[k],l)?id:tag[k];
			return;
		}
		int mid=l+r>>1;
		if(K[id]>K[tag[k]])
		{
			if(val(id,mid)>val(tag[k],mid))
				Modify(k<<1,l,mid,tag[k]),tag[k]=id;
			else
				Modify(k<<1|1,mid+1,r,id);
		}
		else
		{
			if(val(id,mid)>val(tag[k],mid))
				Modify(k<<1|1,mid+1,r,tag[k]),tag[k]=id;
			else
				Modify(k<<1,l,mid,id);
		}
	}
	
	int Query(int k,int l,int r,int x)
	{
		if(l==r)
			return val(tag[k],l);
		int mid=l+r>>1,res=val(tag[k],x);
		if(mid>=x)
			res=max(res,Query(k<<1,l,mid,x));
		else
			res=max(res,Query(k<<1|1,mid+1,r,x));
		return res;
	}
	
	void clear(int k,int l,int r)
	{
		tag[k]=0;
		if(l==r)
			return;
		int mid=l+r>>1;
		clear(k<<1,l,mid);
		clear(k<<1|1,mid+1,r);
	}
}T;

void add(int from,int to)
{
	g[++cnt].nxt=head[from];
	g[cnt].to=to;
	head[from]=cnt;
}

void init()
{
	scanf("%lld",&n);
	for (int i=1,x,y;i<n;i++)
		scanf("%lld %lld",&x,&y),add(x,y),add(y,x);
	for (int i=1;i<=n;i++)
		scanf("%lld",&p[i]);
}

void dfs(int x,int fa)
{
	siz[x]=1;
	for (int i=head[x];i;i=g[i].nxt)
	{
		int v=g[i].to;
		if(v==fa||del[v])
			continue;
		dfs(v,x);
		siz[x]+=siz[v];
	}
}

int Get_Weight(int x)
{
	dfs(x,-1);
	int fa=-1,k=siz[x]/2;
	while(1)
	{
		int tmp=0;
		for (int i=head[x];i;i=g[i].nxt)
		{
			int v=g[i].to;
			if(v==fa||del[v])
				continue;
			if(siz[tmp]<siz[v])
				tmp=v;
		}
		if(siz[tmp]<=k) return x;
		fa=x,x=tmp;
	}
}

void dfs_1(int x,int fa,int pre)
{
	len[x]=len[fa]+1,sum[x]=sum[fa]+p[x],
	_sum[x]=_sum[fa]+pre+p[x],Sum[x]=Sum[fa]+p[x]*(len[x]-1);
	Ans=max(Ans,Sum[x]+sum[x]+p[X]);
//	printf("qwq%lld %lld\n",x,sum[x]);
	for (int i=head[x];i;i=g[i].nxt)
	{
		int v=g[i].to;
		if(v==fa||del[v])
			continue;
		dfs_1(v,x,pre+p[x]);
	}
}

void dfs_2(int x,int fa,int fuck)
{
	bin[++all]=x;
	Ans=max(Ans,T.Query(1,1,fuck,len[x])+_sum[x]);
	for (int i=head[x];i;i=g[i].nxt)
	{
		int v=g[i].to;
		if(v==fa||del[v])
			continue;
		dfs_2(v,x,fuck);
	}
}

void Get_Ans(int x,int fuck)
{
	X=x;
	int CNT=0;
	T.cnt=sum[x]=Sum[x]=0,len[x]=1,_sum[x]=p[x],T.clear(1,1,fuck);
	for (int i=head[x];i;i=g[i].nxt)
	{
		int v=g[i].to;
		if(del[v]) continue;
		b[++CNT]=v;
		dfs_1(v,x,p[x]);
	}
	for (int i=1;i<=CNT;i++)
	{
		all=0;
		dfs_2(b[i],x,fuck);
		for (int j=1;j<=all;j++)
			T.Insert(sum[bin[j]],Sum[bin[j]],fuck);
	}
	T.cnt=0;T.clear(1,1,fuck);
	for (int i=CNT;i>=1;i--)
	{
		all=0;
		dfs_2(b[i],x,fuck);
		for (int j=1;j<=all;j++)
			T.Insert(sum[bin[j]],Sum[bin[j]],fuck);
	}
}

void conquer(int x)
{
	int w=Get_Weight(x);
	del[w]=1;
//	double c1=clock();
	Get_Ans(w,siz[x]);
//	printf("%.2lf\n",(double)(clock()-c1)/CLOCKS_PER_SEC);
	for (int i=head[w];i;i=g[i].nxt)
	{
		int v=g[i].to;
		if(del[v]) continue;
		conquer(v);
	}
}

void work()
{
	conquer(1);
	printf("%lld\n",Ans);
}

signed main()
{
	init();
	work();
	return 0;
}
posted @ 2020-07-11 20:58  With_penguin  阅读(113)  评论(0编辑  收藏  举报