• CF1303G Sum of Prefix Sums


    点分治+李超树

    因为题目要求的是树上所有路径,所以用点分治维护

    因为在点分治的过程中相当于将树上经过当前$root$的一条路径分成了两段

    那么先考虑如何计算两个数组合并后的答案

    记数组$a$,$b$,求得是将$b$数组接到$a$数组的答案

    其$a$,$b$的sum of prefix sums分别为$sa$,$sb$,其中$a$数组所有元素的和为$sum$,$b$数组长度为$l$

    然后整合一下原来计算的式

    其实对于一个数组$P$的sum of prefix sums就是

    $n*p_{1}+(n-1)*p_{2}+(n-2)*p_{3}+...+2*p_{n-1}+1*p_{n}$

    照着这个式子推出来,将$b$数组接到$a$数组的答案是

    $sa+sb+sum*l$

    然后这里可以将$sa$看做截距,$sum$看做斜率,$l$为$x$坐标,最终答案为$y$坐标

    求的就是每一个$sa$为截距,$sum$为斜率的线段在某一点的最大取值

    那么用李超树维护即可

    要注意对于树上两个节点$u$,$v$

    $u$到$v$的答案和$v$到$u$的答案是不一样的

    所以要在合并子树的时候要正着扫一遍,反着扫一遍

    还有如果是只有一颗子树需要特判

      1 #pragma GCC optimize(2)
      2 #include <bits/stdc++.h>
      3 #define int long long
      4 using namespace std;
      5 const int N=150100;
      6 int n,a[N];
      7 int sz[N],vi[N],dfn,MAX,root;
      8 vector <int> e[N];
      9 struct line
     10 {
     11     int k,b;
     12 };
     13 struct node
     14 {
     15     line tag;
     16     int ti;
     17 }sh[N*4];
     18 int cal(int x,line a)
     19 {
     20     return a.k*x+a.b;
     21 }
     22 void change(int x,int l,int r,line k)
     23 {
     24     if (sh[x].ti!=dfn)
     25     {
     26         sh[x].tag=k;
     27         sh[x].ti=dfn;
     28         return;
     29     }
     30     if (cal(l,k)>=cal(l,sh[x].tag) && cal(r,k)>=cal(r,sh[x].tag))
     31     {
     32         sh[x].tag=k;
     33         return;
     34     }
     35     if (cal(l,k)<=cal(l,sh[x].tag) && cal(r,k)<=cal(r,sh[x].tag))
     36       return;
     37     int mid=(l+r)>>1;
     38     if (cal(mid,k)>cal(mid,sh[x].tag)) swap(k,sh[x].tag);
     39     if (cal(l,k)>cal(l,sh[x].tag)) change(x+x,l,mid,k);
     40     else change(x+x+1,mid+1,r,k);
     41 }
     42 int query(int x,int l,int r,int wh)
     43 {
     44     int ans=(sh[x].ti==dfn)?cal(wh,sh[x].tag):0;
     45     if (l==r) return ans;
     46     int mid=(l+r)>>1;
     47     if (wh<=mid) ans=max(ans,query(x+x,l,mid,wh));
     48     else ans=max(ans,query(x+x+1,mid+1,r,wh));
     49     return ans;
     50 }
     51 //李超树
     52 void dfs_insert(int x,int fa,int de,line now)
     53 {
     54     now.k+=a[x];
     55     now.b+=de*a[x];
     56     change(1,1,n,now);
     57     for (register int i=0;i<(int)e[x].size();i++)
     58     {
     59         int u=e[x][i];
     60         if (vi[u] || u==fa) continue;
     61         dfs_insert(u,x,de+1,now);
     62     }
     63 }
     64 void dfs_query(int x,int fa,int de,int sb,int s)
     65 {
     66     sb+=a[x]+s;
     67     s+=a[x];
     68     MAX=max(MAX,query(1,1,n,de)+sb);
     69     for (register int i=0;i<(int)e[x].size();i++)
     70     {
     71         int u=e[x][i];
     72         if (vi[u] || u==fa) continue;
     73         dfs_query(u,x,de+1,sb,s);
     74     }
     75 }
     76 void dfs_size(int x,int fa)
     77 {
     78     sz[x]=1;
     79     for (register int i=0;i<(int)e[x].size();i++)
     80     {
     81         int u=e[x][i];
     82         if (vi[u] || u==fa) continue;
     83         dfs_size(u,x);
     84         sz[x]+=sz[u];
     85     }
     86 }
     87 void dfs_root(int x,int fa,int tot)
     88 {
     89     bool bl=1;
     90     for (register int i=0;i<(int)e[x].size();i++)
     91     {
     92         int u=e[x][i];
     93         if (vi[u] || u==fa) continue;
     94         dfs_root(u,x,tot);
     95         if (sz[u]>tot/2) bl=0;
     96     }
     97     if (tot-sz[x]>tot/2) bl=0;
     98     if (bl) root=x;
     99 }
    100 void dfs(int x,int fa,int de,int sa,int sb,int s)
    101 {
    102     sa+=de*a[x];
    103     sb+=s+a[x];
    104     s+=a[x];
    105     MAX=max(MAX,sb);
    106     MAX=max(MAX,sa);
    107     for (register int i=0;i<(int)e[x].size();i++)
    108     {
    109         int u=e[x][i];
    110         if (vi[u] || u==fa) continue;
    111         dfs(u,x,de+1,sa,sb,s);
    112     }
    113 }
    114 void divide(int x)//点分治
    115 {
    116     dfn++;
    117     vi[x]=1;
    118     int cnt=0;
    119     for (register int i=0;i<(int)e[x].size();i++)
    120     {
    121         int u=e[x][i];
    122         if (vi[u]) continue;
    123         cnt++;
    124         line tmp;
    125         tmp.k=tmp.b=0;
    126         if (cnt!=1) dfs_query(u,x,2,a[x],a[x]);
    127         dfs_insert(u,x,1,tmp);
    128     }
    129     bool bl=(cnt==1);
    130     dfn++;cnt=0;
    131     for (register int i=(int)e[x].size()-1;i>=0;i--)//反着扫描
    132     {
    133         int u=e[x][i];
    134         if (vi[u]) continue;
    135         if (bl) dfs(u,x,2,a[x],a[x],a[x]);//只有一颗子树时的特判
    136         cnt++;
    137         line tmp;
    138         tmp.k=tmp.b=0;
    139         if (cnt!=1) dfs_query(u,x,2,a[x],a[x]);
    140         dfs_insert(u,x,1,tmp);
    141     }
    142     for (register int i=0;i<(int)e[x].size();i++)
    143     {
    144         int u=e[x][i];
    145         if (vi[u]) continue;
    146         dfs_size(u,x);
    147         dfs_root(u,x,sz[u]);
    148         divide(root);
    149     }
    150 }
    151 signed main()
    152 {
    153     scanf("%lld",&n);
    154     for (int i=1;i<n;i++)
    155     {
    156         int u,v;
    157         scanf("%lld%lld",&u,&v);
    158         e[u].push_back(v);
    159         e[v].push_back(u);
    160     }
    161     for (int i=1;i<=n;i++)
    162     {
    163         scanf("%lld",&a[i]);
    164         MAX=max(MAX,a[i]);
    165     }
    166     dfs_size(1,-1);
    167     dfs_root(1,-1,sz[1]);
    168     divide(root);
    169     printf("%lld
    ",MAX);
    170 }
    View Code
  • 相关阅读:
    java抽象类
    java不支持多继承
    logback颜色
    @ConfigurationProperties、@Value、@PropertySource
    redis命令
    mac下安装rabbitmq
    mac下安装jmeter
    python TypeError: 'int' object is not callable 问题解决
    白炽灯串联发光问题_高中知识(原创)
    python 离散序列 样本数伸缩(原创)
  • 原文地址:https://www.cnblogs.com/huangchenyan/p/12358085.html
Copyright © 2020-2023  润新知