Code Chef TSUM2(动态凸包+点分治)

题面

传送门

题解

真是毒瘤随机化算法居然一分都不给

首先这种树上的题目一般想到的都是点分

我们考虑如何统计经过当前点的路径的贡献,设当前点\(u\)在序列中是第\(c\)个,那么一条路径的贡献就是

\[Ans=\sum_{i=1}^k i\times w_{p_i}=\sum_{i=1}^ci\times w_{p_i}+\sum_{i=c+1}^ki\times w_{p_i} \]

其中前面是从子树到\(u\)的路径,后面是从\(u\)到子树里的路径

然后拆一下

\[Ans=c\times \sum_{i=c+1}^kw_{p_i}+\sum_{i=c+1}^k (i-c)w_{p_i}+\sum_{i=1}^k i\times w_{p_i} \]

如果我们把这看成一条直线,形如\(y=kx+b\),其中\(k=c\)\(b=\sum_{i=1}^k i\times w_{p_i}\),那么这就是要求我们对于处理所有从\(u\)到子树的路径中,令\(x=\sum\limits_{i=c+1}^kw_{p_i}\)最大的\(y\)(因为对于一条固定的路径来说\(\sum\limits_{i=c+1}^k (i-c)w_{p_i}\)是个常数)

那么现在问题就变成了动态插入直线,动态维护最大值。可以李超线段树也可以动态凸包

不过因为路径是有序的,所以对于儿子需要正着跑一遍,倒着跑一遍

话说为啥我到了现在还会打错点分啊喂……

鉴于这玩意儿太难码了我代码直接抄zyy的了

//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=1e5+5;const ll inf=(1ll<<60);
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
bool qwq;
struct Line;typedef set<Line>::iterator IT;
struct Line{
	ll k,b;mutable ll p;
	inline Line(){}
	inline Line(R ll kk,R ll bb,R ll pp):k(kk),b(bb),p(pp){}
	inline bool operator <(const Line &b)const{return qwq?p<b.p:k<b.k;}
};
struct node{
	multiset<Line>s;
	bool inter(IT x,IT y){
		if(y==s.end())return x->p=inf,0;
		if(x->k==y->k)x->p=x->b>y->b?inf:-inf;
			else x->p=(y->b-x->b)/(x->k-y->k);
		return x->p>=y->p;
	}
	void ins(R ll k,R ll b){
		IT it,z=s.insert(Line(k,b,0)),y=z++,x=y;
		for(;inter(y,z);it=z,++z,s.erase(it));
		if(x!=s.begin()&&inter(--x,y))it=y,++y,s.erase(it),inter(x,y);
		for(;(y=x)!=s.begin()&&(--x)->p>=y->p;it=y,++y,s.erase(it),inter(x,y));
	}
	ll ask(R ll x){
		qwq=1;IT res=s.lower_bound(Line(0,0,x));qwq=0;
		return res==s.end()?-1e18:res->k*x+res->b;
	}
};
int w[N],sz[N],mx[N],rt,size;ll res;bool vis[N];
int n;
void findrt(int u,int fa){
	sz[u]=1,mx[u]=0;
	go(u)if(!vis[v]&&v!=fa)findrt(v,u),sz[u]+=sz[v],cmax(mx[u],sz[v]);
	cmax(mx[u],size-sz[u]);
	if(mx[u]<mx[rt])rt=u;
}
void dfs1(int u,int fa,ll b,int d,ll x,node &s){
	cmax(res,b+s.ask(x));
	go(u)if(v!=fa&&!vis[v])dfs1(v,u,b+w[v]*(d+1),d+1,x+w[v],s);
}
void dfs2(int u,int fa,ll b,ll sum,int d,node &s){
	s.ins(d,b);
	go(u)if(v!=fa&&!vis[v])dfs2(v,u,b+sum+w[v],sum+w[v],d+1,s);
}
void solve(int u){
	vis[u]=1;
	static int st[N];int top=0;
	node s1,s2;s1.ins(1,w[u]);
	go(u)if(!vis[v]){
		st[++top]=v;
		dfs1(v,u,w[v],1,w[v],s1);
		dfs2(v,u,w[v]+(w[u]<<1),w[v]+w[u],2,s1);
	}
	for(R int i=top,v;i&&(v=st[i]);--i){
		dfs1(v,u,w[v],1,w[v],s2);
		dfs2(v,u,w[v]+(w[u]<<1),w[v]+w[u],2,s2);
	}
	cmax(res,s2.ask(0)),cmax(res,1ll*w[u]);
	int s=size;
	go(u)if(!vis[v]){
		rt=0,size=sz[v]>sz[u]?s-sz[u]:sz[v],findrt(v,0);
		solve(rt);
	}
}
int main(){
//	freopen("testdata.in","r",stdin);
	for(int T=read();T;--T){
		n=read(),res=-inf;
		fp(i,1,n)w[i]=read();
		for(R int i=1,u,v;i<n;++i)u=read(),v=read(),add(u,v),add(v,u);
		mx[0]=n+1,rt=0,size=n,findrt(1,0),solve(rt);
		printf("%lld\n",res);
		memset(head,0,(n+1)<<2);
		memset(vis,0,n+1);
		tot=0;
	}
	return 0;
}
posted @ 2019-04-18 20:36  bztMinamoto  阅读(287)  评论(0编辑  收藏  举报
Live2D