ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[cf1458F]Range Diameter Sum

2022-06-29 09:05:37  阅读:168  来源: 互联网

标签:Diameter sz int mid fa Range cf1458F dep dis


考虑分治,分别求出左侧后缀和右侧前缀的直径,即需将两者两两合并:

将直径以长度和中心点(将边拆点,使长度为偶数)的方式描述,分别记为$d$和$u$

此时,对于$(d_{1},u_{1})$和$(d_{2},u_{2})$,合并后的直径长度即$\max\{d_{1},d_{2},\frac{d_{1}+d_{2}}{2}+dis(u_{1},u_{2})\}$

若直径两端点均出自某侧内部,显然即$\max\{d_{1},d_{2}\}$

若直径两端点分别出自两侧,显然$dis(x,u)\le \frac{d}{2}$,进而
$$
dis(x,y)\le dis(x,u_{1})+dis(u_{1},u_{2})+dis(u_{2},y)\le \frac{d_{1}+d_{2}}{2}+dis(u_{1},u_{2})
$$
同时,每条直径的两端点中总有一个(相对中心点)与另一条直径不在同侧,即可取到等号

在此基础上,当确定一侧后,直径单调"偏移",即$d_{1}\rightarrow \frac{d_{1}+d_{2}}{2}+dis(u_{1},u_{2})\rightarrow d_{2}$

用双指针维护三者分界点,关于$d_{1},d_{2}$的项均易处理,下面考虑$dis(u_{1},u_{2})$

换言之,即维护一个集合$S$,支持加减元素和查询$\sum_{y\in S}d(x,y)$,进而用点分树维护即可

时间复杂度为$o(n\log^{2}n)$,可以通过

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 200005
  4 #define ll long long
  5 int n,x,y,dep[N],d[N],u[N],fa[N][20];
  6 ll ans,sum[N];vector<int>e[N];
  7 void dfs(int k,int f,int s){
  8     dep[k]=s,fa[k][0]=f;
  9     for(int i=1;i<20;i++)fa[k][i]=fa[fa[k][i-1]][i-1];
 10     for(int i:e[k])
 11         if (i!=f)dfs(i,k,s+1);
 12 }
 13 int lca(int x,int y){
 14     if (dep[x]<dep[y])swap(x,y);
 15     for(int i=19;i>=0;i--)
 16         if (dep[fa[x][i]]>=dep[y])x=fa[x][i];
 17     if (x==y)return x;
 18     for(int i=19;i>=0;i--)
 19         if (fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
 20     return fa[x][0];
 21 }
 22 int dis(int x,int y){
 23     return dep[x]+dep[y]-(dep[lca(x,y)]<<1);
 24 }
 25 int get_mid(int x,int y,int z){
 26     if (dep[x]<dep[y])swap(x,y);
 27     for(int i=0;i<20;i++)
 28         if ((z>>i)&1)x=fa[x][i];
 29     return x;
 30 }
 31 namespace DIVIDE{
 32     int rt,vis[N],sz[N],dep[N],fa[N],cnt1[N],cnt2[N],d[N][20];
 33     ll sum1[N],sum2[N];vector<int>v;
 34     void get_sz(int k,int fa){
 35         sz[k]=1;
 36         for(int i:e[k])
 37             if ((!vis[i])&&(i!=fa))get_sz(i,k),sz[k]+=sz[i];
 38     }
 39     void get_rt(int k,int fa,int s){
 40         int mx=s-sz[k];
 41         for(int i:e[k])
 42             if ((!vis[i])&&(i!=fa))get_rt(i,k,s),mx=max(mx,sz[i]);
 43         if (mx<=(s>>1))rt=k;
 44     }
 45     void get_dis(int k,int fa,int s){
 46         d[k][dep[s]]=dis(k,s);
 47         for(int i:e[k])
 48             if ((!vis[i])&&(i!=fa))get_dis(i,k,s);
 49     }
 50     int dfs(int k,int s){
 51         get_sz(k,0),get_rt(k,0,sz[k]);
 52         k=rt,vis[k]=1,dep[k]=s,get_dis(k,0,k);
 53         for(int i:e[k])
 54             if (!vis[i])fa[dfs(i,s+1)]=k;
 55         return k;
 56     }
 57     void add(int k,int p){
 58         for(int i=k;i;i=fa[i]){
 59             cnt1[i]+=p,sum1[i]+=p*d[k][dep[i]];
 60             if (fa[i])cnt2[i]+=p,sum2[i]+=p*d[k][dep[fa[i]]];
 61         }
 62     }
 63     ll query(int k){
 64         ll ans=0;
 65         for(int i=k;i;i=fa[i]){
 66             ans+=(ll)cnt1[i]*d[k][dep[i]]+sum1[i];
 67             if (fa[i])ans-=(ll)cnt2[i]*d[k][dep[fa[i]]]+sum2[i];
 68         }
 69         return ans;
 70     }
 71 };
 72 void solve(int l,int r){
 73     if (l==r)return;
 74     int mid=(l+r>>1);
 75     x=y=u[mid]=mid,d[mid]=0;
 76     for(int i=mid-1;i>=l;i--){
 77         int dx=dis(i,x),dy=dis(i,y);
 78         if (max(dx,dy)<d[i+1])d[i]=d[i+1];
 79         else{
 80             d[i]=max(dx,dy);
 81             if (dx<dy)x=i;else y=i;
 82         }
 83         u[i]=get_mid(x,y,(d[i]>>1));
 84     }
 85     x=y=u[mid+1]=mid+1,d[mid+1]=0;
 86     for(int i=mid+2;i<=r;i++){
 87         int dx=dis(i,x),dy=dis(i,y);
 88         if (max(dx,dy)<d[i-1])d[i]=d[i-1];
 89         else{
 90             d[i]=max(dx,dy);
 91             if (dx<dy)x=i;else y=i;
 92         }
 93         u[i]=get_mid(x,y,(d[i]>>1));
 94     }
 95     x=y=mid,sum[l-1]=0;
 96     for(int i=l;i<=mid;i++)sum[i]=sum[i-1]+d[i];
 97     for(int i=mid+1;i<=r;i++){
 98         while ((l<=x)&&(d[x]<(d[i]+d[x]>>1)+dis(u[i],u[x])))DIVIDE::add(u[x--],1);
 99         while ((x<y)&&((d[i]+d[y]>>1)+dis(u[i],u[y])<d[i]))DIVIDE::add(u[y--],-1);
100         ans+=(sum[x]+sum[y]>>1)+(ll)(y-x)*(d[i]>>1)+DIVIDE::query(u[i])+(ll)(mid-y)*d[i];
101     }
102     while (x<y)DIVIDE::add(u[y--],-1);
103     solve(l,mid),solve(mid+1,r);
104 }
105 int main(){
106     scanf("%d",&n);
107     for(int i=1;i<n;i++){
108         scanf("%d%d",&x,&y);
109         e[x].push_back(i+n),e[i+n].push_back(x);
110         e[y].push_back(i+n),e[i+n].push_back(y);
111     }
112     dfs(1,0,1),DIVIDE::dfs(1,1);
113     solve(1,n),printf("%lld\n",(ans>>1));
114     return 0;
115 }
View Code

 

标签:Diameter,sz,int,mid,fa,Range,cf1458F,dep,dis
来源: https://www.cnblogs.com/PYWBKTDA/p/16421934.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有