CF1303G

Posted chasedeath

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1303G相关的知识,希望对你有一定的参考价值。

CF1303G - Sum of Prefix Sums

题目大意

定义一个数列的\\(a_1,a_2,\\cdots a_n\\)的权值为\\(\\sum (n-i+1)a_i\\)

对于一棵带点权的树,求所有路径数列最大的权值


分析

首先对于路径问题可以考虑无脑树分治

假设确定一条路径到达根的\\(b_1,b_2,\\cdots b_m\\),一条从根出发的路径\\(c_1,c_2,\\cdots c_k\\)

\\(s_1=\\sum (m-i+1)b_i,s_2=\\sum b_i\\)\\(s_3=\\sum (k-i+1)c_i\\)

则易知其贡献为\\(s_1+s2\\cdot k+s_3\\)

考虑这是一个斜率优化的形式,可以通过凸包维护

但是不同的实现方法有很多,复杂度为基本上都是\\(O(n\\log ^2n)\\)

比如:

1.点分治+分治合并凸包+分治合并查询

2.点分治+李超树

3.边分治+凸包(需要\\(sort\\),说不定不用?)

我无脑李超树

const int N=2e5+10,INF=1e9+10;

int n,m,a[N];
vector <int> G[N];
struct Node{
	ll k,b;
	Node(){}
	Node(ll k,ll b):k(k),b(b){}
	ll operator [] (ll x) const { return k*x+b; }
} s[N];
int ls[N],rs[N],cnt;
int New(){
	int u=++cnt;
	ls[u]=rs[u]=0,s[u]=Node(-INF,-INF);
	return u;
}
void Upd(int &p,int l,int r,Node x){
	if(x.k<0) return;
	if(!p) p=New();
	int mid=(l+r)>>1;
	if(s[p][mid]<x[mid]) swap(s[p],x);
	if(l==r) return;
	if(x[l]>s[p][l]) Upd(ls[p],l,mid-1,x);
	if(x[r]>s[p][r]) Upd(rs[p],mid+1,r,x);
}
ll Que(int p,int l,int r,int x){
	if(l==r) return s[p][x];
	int mid=(l+r)>>1;
	return max(s[p][x],x<=mid?Que(ls[p],l,mid,x):Que(rs[p],mid+1,r,x));
}

int vis[N],mi=1e9,rt,sz[N];
void FindRt(int n,int u,int f){
	int ma=0; sz[u]=1;
	for(int v:G[u]) if(v!=f && !vis[v]) {
		FindRt(n,v,u);
		cmax(ma,sz[v]),sz[u]+=sz[v];
	}
	cmax(ma,n-sz[u]);
	if(mi>ma) mi=ma,rt=u;
}

ll s1[N],s2[N],s3[N],s4[N],dep[N];
int L[N],I[N],dfn,R[N];
void dfs(int u,int f){
	dep[u]=dep[f]+1;
	s2[u]=s2[f]+a[u],s1[u]=s1[f]+1ll*a[u]*(dep[u]+1);
	s4[u]=s4[f]+a[u],s3[u]=s3[f]+s4[u];
	I[L[u]=++dfn]=u;
	for(int v:G[u]) if(v!=f && !vis[v]) dfs(v,u);
	R[u]=dfn;
}
ll ans;
void Div(int n,int u){
	mi=1e9,FindRt(n,u,0),vis[u=rt]=1;
	s1[u]=s2[u]=a[u],s3[u]=s4[u]=dep[u]=0;
	
	I[L[u]=dfn=1]=u;
	for(int v:G[u]) if(!vis[v]) dfs(v,u);
	R[u]=dfn;

	cmax(ans,(ll)a[u]),cnt=rt=0;
	Upd(rt,1,dfn,Node(s2[u],s1[u]));
	for(int v:G[u]) if(!vis[v]) {
		rep(j,L[v],R[v]) {
			int i=I[j];
			cmax(ans,Que(rt,1,dfn,dep[i])+s3[i]);
		}
		rep(j,L[v],R[v]) {
			int i=I[j];
			Upd(rt,1,dfn,Node(s2[i],s1[i]));
		}
	}
	cnt=rt=0;
	drep(k,G[u].size()-1,0) {
		int v=G[u][k];
		if(vis[v]) continue;
		rep(j,L[v],R[v]) {
			int i=I[j];
			cmax(ans,Que(rt,1,dfn,dep[i])+s3[i]);
		}
		rep(j,L[v],R[v]) {
			int i=I[j];
			Upd(rt,1,dfn,Node(s2[i],s1[i]));
		}
	}
	cmax(ans,Que(rt,1,dfn,dep[u])+s3[u]);
	for(int v:G[u]) if(!vis[v]) {
		if(sz[v]>sz[u]) sz[v]=n-sz[u];
		Div(sz[v],v);
	}
}

int main(){
	s[0]=Node(-1,-INF);
	n=rd();
	rep(i,2,n) {
		int u=rd(),v=rd();
		G[u].pb(v),G[v].pb(u);
	}
	rep(i,1,n) a[i]=rd();
	Div(n,1);
	printf("%lld\\n",ans);
}

以上是关于CF1303G的主要内容,如果未能解决你的问题,请参考以下文章

CF1303G Sum of Prefix Sums

CF1303G Sum of Prefix Sums[李超树,点分治]

CF1303G Sum of Prefix Sums[李超树,点分治]

如何从后台弹出片段

cf 模拟

CF1435 游记