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;
}

猜你喜欢

转载自www.cnblogs.com/bztMinamoto/p/10732175.html