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


    题面

    传送门

    题解

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

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

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

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

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

    然后拆一下

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

    如果我们把这看成一条直线,形如(y=kx+b),其中(k=c)(b=sum_{i=1}^k i imes w_{p_i}),那么这就是要求我们对于处理所有从(u)到子树的路径中,令(x=sumlimits_{i=c+1}^kw_{p_i})最大的(y)(因为对于一条固定的路径来说(sumlimits_{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
    ",res);
    		memset(head,0,(n+1)<<2);
    		memset(vis,0,n+1);
    		tot=0;
    	}
    	return 0;
    }
    
  • 相关阅读:
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    线性表——数组实现
    this指针与const成员函数
    类对象拷贝是不是赋值操作??
    你真的理解内联函数吗?
    名字查找先于类型检查:函数重载与作用域
    谈谈函数调用
    推荐形参使用常量引用:void func(const T &);
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10732175.html
Copyright © 2020-2023  润新知