• CF1303G Sum of Prefix Sums


    考虑点分治。

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

    我们把 (sumlimits_{j=1}^{m}b[j]) (斜率)和 (sumlimits_{j=1}^{m}j imes 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
    ",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
    ",(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
    ",Ans);
    }
    
    signed main()
    {
    	init();
    	work();
    	return 0;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    《把时间当作朋友》后记
    《把时间当作朋友》 李笑来
    chrome 和 IE 下 new Date()的不同 导致ajax出错
    ruby vim环境设置
    ASP.NET UserControl传递参数
    win2008 IIS7 ASP 的 405 错误
    天使的微笑——《天使爱美丽》
    随机点击表中某一行
    页面刷新方法
    随机选择下拉列表中的值
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13285456.html
Copyright © 2020-2023  润新知