cf1089d Distance Sum

题目大意

给一个有n个点,m条边的无向连通图,求所有点两两之间的最短路。$(2<=n<=10^5;n-1<=m<=n+42)$

solution

我们注意到$m-n+1$很小。先任意求一棵生成树,然后将剩余$m-n+1$条边涉及的点建一棵虚树。分类讨论如下情况即可:

(1)不属于虚树上任意一条边的点到所有点的贡献;单次操作$O(1)$(合并到虚树边上的点)

(2)一个点到同一条边内其它点的最短路和(非关键点);单次操作$O(1)$

(3)一个在虚树上某条边的点(包括关键点)到其它边内非关键点的贡献。单次操作$O(m-n+1)$

(4)关键点到关键点的最短路和。$O((m-n+1)*$最短路复杂度$)$

用前缀和和后缀和优化即可,时间复杂度为$O(m(m-n+1))$。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 #define ot original_tree
  6 #define vt virtual_tree
  7 typedef long long ll;
  8 const int LEN=2000000;
  9 char str[2000010];int pos=0;
 10 inline int rd(){
 11     char c=str[pos++];int x=0,flag=1;
 12     for(;c<'0'||c>'9';c=str[pos++])if(c=='-')flag=-1;
 13     for(;c>='0'&&c<='9';c=str[pos++])x=x*10+c-'0';
 14     return x*flag;
 15 }
 16 const int N=120010,M=1010;
 17 int n,m;ll ans=0;
 18 inline int min_(int x,int y){
 19     return (x<=y)?x:y;
 20 }
 21 namespace original_tree{
 22     struct tree{int dep,dfn,sz,fa[20];}t[N];
 23     struct edge{int to,nxt;}e[N<<1];
 24     int tim=0,cur[N]={0},head[N]={0};
 25     bool tag[N]={false};
 26     void dfs(int u){
 27         for(int i=1;i<20;i++)
 28             t[u].fa[i]=t[t[u].fa[i-1]].fa[i-1];
 29         t[u].sz=1;cur[t[u].dfn=++tim]=u;
 30         for(int i=head[u];i;i=e[i].nxt){
 31             int v=e[i].to;
 32             if(t[v].sz)
 33                 continue;
 34             tag[(i>m)?i-m:i]=true;
 35             t[v].dep=t[u].dep+1;
 36             t[v].fa[0]=u;dfs(v);
 37             t[u].sz+=t[v].sz;
 38         }
 39         return;
 40     }
 41     void build(){
 42         memset(t,0,sizeof(t));
 43         for(int i=1;i<=m;i++){
 44             int u=rd(),v=rd();
 45             e[i]=(edge){v,head[u]};head[u]=i;
 46             e[m+i]=(edge){u,head[v]};head[v]=m+i;
 47         }
 48         dfs(1);
 49         return;
 50     }
 51     inline int lca(int u,int v){
 52         if(t[u].dep<t[v].dep)
 53             swap(u,v);
 54         int delta=t[u].dep-t[v].dep;
 55         for(int i=0;i<20;i++)
 56             if(delta&(1<<i))
 57                 u=t[u].fa[i];
 58         for(int i=19;~i;i--)
 59             if(t[u].fa[i]!=t[v].fa[i]){
 60                 u=t[u].fa[i];
 61                 v=t[v].fa[i];
 62             }
 63         return (u==v)?u:t[u].fa[0];
 64     }
 65     void solve(int u){
 66         for(int i=head[u];i;i=e[i].nxt){
 67             int v=e[i].to;
 68             if(u!=t[v].fa[0])
 69                 continue;
 70             ans+=(ll)t[v].sz*(n-t[v].sz);
 71             solve(v);
 72         }
 73         return;
 74     }
 75 }
 76 namespace virtual_tree{
 77     struct edge{int to,nxt,dis;}e[M<<1];
 78     int cnt=0,head[M]={0};bool inv[N]={false};
 79     int num=0,vid[M],id[N]={0},fa[M]={0};
 80     int top=0,st[M];bool choose[N]={false};
 81     int dis[M][M];bool inq[M]={false};
 82     ll pre[N]={0},suf[N]={0},p[N]={0},s[N]={0};
 83     int sz[N]={0},len[M],vis[N]={0};
 84     int ql,qr,q[N];
 85     inline void link(int u,int v,int w){
 86         e[++cnt]=(edge){v,head[u],w};
 87         head[u]=cnt;
 88         e[++cnt]=(edge){u,head[v],w};
 89         head[v]=cnt;
 90         return;
 91     }
 92     void build(){
 93         for(int i=1;i<=m;i++)
 94             if(!ot::tag[i]){
 95                 choose[ot::e[i].to]=true;
 96                 choose[ot::e[m+i].to]=true;
 97             }
 98         vid[id[st[++top]=1]=++num]=1;
 99         for(int i=2;i<=n;i++){
100             int x=ot::cur[i];
101             if(!choose[x])
102                 continue;
103             int pre=ot::lca(x,st[top]);
104             for(;top>1&&ot::t[st[top-1]].dep>=ot::t[pre].dep;top--){
105                 link(id[st[top]],id[st[top-1]],ot::t[st[top]].dep-ot::t[st[top-1]].dep);
106                 fa[id[st[top]]]=id[st[top-1]];
107             }
108             if(st[top]!=pre){
109                 link(id[st[top]],id[pre]=++num,ot::t[st[top]].dep-ot::t[pre].dep);
110                 fa[id[st[top]]]=id[pre];vid[num]=st[top]=pre;
111             }
112             vid[id[st[++top]=x]=++num]=x;
113         }
114         for(int i=top;i>1;i--){
115             link(id[st[i]],id[st[i-1]],ot::t[st[i]].dep-ot::t[st[i-1]].dep);
116             fa[id[st[i]]]=id[st[i-1]];
117         }
118         for(int i=1;i<=m;i++)
119             if(!ot::tag[i])
120                 link(id[ot::e[i].to],id[ot::e[m+i].to],1);
121         return;
122     }
123     void spfa(){
124         memset(dis,0x3f,sizeof(dis));
125         for(int x=1;x<=num;x++){
126             q[ql=qr=1]=x;dis[x][x]=0;inq[x]=true;
127             while(ql<=qr){
128                 int u=q[ql++];inq[u]=false;
129                 for(int i=head[u];i;i=e[i].nxt){
130                     int v=e[i].to;
131                     if(dis[x][v]>dis[x][u]+e[i].dis){
132                         dis[x][v]=dis[x][u]+e[i].dis;
133                         if(!inq[v])
134                             inq[q[++qr]=v]=true;
135                     }
136                 }
137             }
138         }
139         return;
140     }
141     void solve(){
142         for(int i=2;i<=num;i++)
143             for(int u=vid[i];u!=vid[fa[i]];u=ot::t[u].fa[0])
144                 inv[u]=true;
145         inv[1]=true;
146         for(int u=1;u<=n;u++){
147             if(!inv[u])
148                 continue;
149             sz[u]=1;
150             for(int i=ot::head[u];i;i=ot::e[i].nxt){
151                 int v=ot::e[i].to,pos=ot::t[v].sz;
152                 if(inv[v])
153                     continue;
154                 ans+=(ll)pos*(n-pos);sz[u]+=pos;
155                 ot::solve(v);
156             }
157         }
158         for(int i=2;i<=num;i++)
159             len[i]=ot::t[vid[i]].dep-ot::t[vid[fa[i]]].dep-1;
160         for(int x=2;x<=num;x++){
161             if(!len[x])continue;
162             pre[len[x]+1]=p[len[x]+1]=suf[len[x]+1]=s[len[x]+1]=0;
163             for(int i=1,u=ot::t[vid[x]].fa[0];i<=len[x];i++,u=ot::t[u].fa[0])
164                 pre[i]=pre[i-1]+(ll)i*sz[u],p[i]=p[i-1]+sz[u];
165             for(int i=1,u=ot::t[vid[x]].fa[0];i<=len[x];i++,u=ot::t[u].fa[0])
166                 suf[i]=(ll)(len[x]-i+1)*sz[u],s[i]=sz[u];
167             for(int i=len[x]-1;i;i--)
168                 suf[i]+=suf[i+1],s[i]+=s[i+1];
169             int dist=dis[x][fa[x]],dep1=ot::t[vid[x]].dep;ll val=0;
170             for(int u=ot::t[vid[x]].fa[0];u!=vid[fa[x]];u=ot::t[u].fa[0]){
171                 int now=dep1-ot::t[u].dep,d=min_(now,len[x]-now+1);ll res=0;
172                 res+=pre[now+d-1]-pre[now-1]-(p[now+d-1]-p[now-1])*now;
173                 res+=suf[now-d+1]-suf[now+1]-(s[now-d+1]-s[now+1])*(len[x]-now+1);
174                 if(now==len[x]-now+1){
175                     val+=res*sz[u];
176                     continue;
177                 }
178                 int l=now-d,r=now+d;
179                 if(r==len[x]+1){
180                     if(l<=dist+1)
181                         res+=suf[1]-suf[l+1]-(s[1]-s[l+1])*(len[x]-now+1);
182                     else{
183                         int h=(l-dist-1)>>1,tg=(l-dist-1)&1;
184                         res+=pre[h+tg]+p[h+tg]*(len[x]-now+1+dist);
185                         res+=suf[l-dist-h]-suf[l+1]-(s[l-dist-h]-s[l+1])*(len[x]-now+1);
186                     }
187                 }
188                 else{
189                     if(len[x]-r+1<=dist+1)
190                         res+=pre[len[x]]-pre[r-1]-(p[len[x]]-p[r-1])*now;
191                     else{
192                         int h=(len[x]-r-dist)>>1,tg=(len[x]-r-dist)&1;
193                         res+=pre[r+dist+h]-pre[r-1]-(p[r+dist+h]-p[r-1])*now;
194                         res+=suf[len[x]-h-tg+1]+s[len[x]-h-tg+1]*(now+dist);
195                     }
196                 }
197                 val+=res*sz[u];
198             }//point in the same edge
199             ans+=val>>1;
200             for(int y=2;y<x;y++){
201                 int dist1=0,dist2=len[y]+1;
202                 for(int u=ot::t[vid[y]].fa[0];u!=vid[fa[y]];u=ot::t[u].fa[0]){
203                     ll val=0;dist1++;dist2--;
204                     int dis1=min_(dist1+dis[x][y],dist2+dis[x][fa[y]]);
205                     int dis2=min_(dist1+dis[fa[x]][y],dist2+dis[fa[x]][fa[y]]);
206                     int d=abs(dis1-dis2);
207                     if(d>=len[x]){
208                         if(dis1<=dis2)
209                             ans+=(pre[len[x]]+p[len[x]]*dis1)*sz[u];
210                         else
211                             ans+=(suf[1]+s[1]*dis2)*sz[u];
212                         continue;
213                     }
214                     int h=(len[x]-d)>>1,tg=(len[x]-d)&1;
215                     if(dis1<=dis2){
216                         val+=pre[d+h+tg]+p[d+h+tg]*dis1;
217                         val+=suf[len[x]-h+1]-suf[len[x]+1]+(s[len[x]-h+1]-s[len[x]+1])*dis2;
218                     }
219                     else{
220                         val+=pre[h+tg]+p[h+tg]*dis1;
221                         val+=suf[len[x]-d-h+1]+s[len[x]-d-h+1]*dis2;
222                     }
223                     ans+=val*sz[u];
224                 }
225             }//edge to edge
226             for(int i=1;i<=num;i++){
227                 int dis1=dis[x][i],dis2=dis[fa[x]][i];
228                 int d=abs(dis1-dis2);ll val=0;
229                 if(d>=len[x]){
230                     if(dis1<=dis2)
231                         ans+=(pre[len[x]]+p[len[x]]*dis1)*sz[vid[i]];
232                     else
233                         ans+=(suf[1]+s[1]*dis2)*sz[vid[i]];
234                     continue;
235                 }
236                 int h=(len[x]-d)>>1,tg=(len[x]-d)&1;
237                 if(dis1<=dis2){
238                     val+=pre[d+h+tg]+p[d+h+tg]*dis1;
239                     val+=suf[len[x]-h+1]-suf[len[x]+1]+(s[len[x]-h+1]-s[len[x]+1])*dis2;
240                 }
241                 else{
242                     val+=pre[h+tg]+p[h+tg]*dis1;
243                     val+=suf[len[x]-d-h+1]+s[len[x]-d-h+1]*dis2;
244                 }
245                 ans+=val*sz[vid[i]];
246             }//key point to edge
247         }
248         for(int i=1;i<num;i++)
249             for(int j=i+1;j<=num;j++)
250                 ans+=(ll)sz[vid[i]]*sz[vid[j]]*dis[i][j];
251         return;
252     }
253 }
254 int main(){
255     fread(str,1,LEN,stdin);
256     n=rd();m=rd();ot::build();
257     vt::build();vt::spfa();
258     vt::solve();
259     printf("%lld\n",ans);
260     return 0;
261 }
posted @ 2019-04-12 13:28  乖巧的小团子QwQ  阅读(308)  评论(0编辑  收藏  举报