CF1303G Sum of Prefix Sums
考虑点分治。
考虑如何合并线段 \(\sum\limits_{i=1}^{n}i\times a[i]\) 和 \(\sum\limits_{j=1}^{m}j\times b[j]\)。新线段的表达式 \(\sum\limits_{i=1}^{n}i\times a[i] + \sum\limits_{j=1}^{m}j\times b[j] + n\times \sum\limits_{j=1}^{m}b[j]\)。
我们把 \(\sum\limits_{j=1}^{m}b[j]\) (斜率)和 \(\sum\limits_{j=1}^{m}j\times 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\n",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\n",(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\n",Ans);
}
signed main()
{
init();
work();
return 0;
}
由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!