题目大意

给一个有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))$。

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ot original_tree
#define vt virtual_tree
typedef long long ll;
const int LEN=;
char str[];int pos=;
inline int rd(){
char c=str[pos++];int x=,flag=;
for(;c<''||c>'';c=str[pos++])if(c=='-')flag=-;
for(;c>=''&&c<='';c=str[pos++])x=x*+c-'';
return x*flag;
}
const int N=,M=;
int n,m;ll ans=;
inline int min_(int x,int y){
return (x<=y)?x:y;
}
namespace original_tree{
struct tree{int dep,dfn,sz,fa[];}t[N];
struct edge{int to,nxt;}e[N<<];
int tim=,cur[N]={},head[N]={};
bool tag[N]={false};
void dfs(int u){
for(int i=;i<;i++)
t[u].fa[i]=t[t[u].fa[i-]].fa[i-];
t[u].sz=;cur[t[u].dfn=++tim]=u;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(t[v].sz)
continue;
tag[(i>m)?i-m:i]=true;
t[v].dep=t[u].dep+;
t[v].fa[]=u;dfs(v);
t[u].sz+=t[v].sz;
}
return;
}
void build(){
memset(t,,sizeof(t));
for(int i=;i<=m;i++){
int u=rd(),v=rd();
e[i]=(edge){v,head[u]};head[u]=i;
e[m+i]=(edge){u,head[v]};head[v]=m+i;
}
dfs();
return;
}
inline int lca(int u,int v){
if(t[u].dep<t[v].dep)
swap(u,v);
int delta=t[u].dep-t[v].dep;
for(int i=;i<;i++)
if(delta&(<<i))
u=t[u].fa[i];
for(int i=;~i;i--)
if(t[u].fa[i]!=t[v].fa[i]){
u=t[u].fa[i];
v=t[v].fa[i];
}
return (u==v)?u:t[u].fa[];
}
void solve(int u){
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(u!=t[v].fa[])
continue;
ans+=(ll)t[v].sz*(n-t[v].sz);
solve(v);
}
return;
}
}
namespace virtual_tree{
struct edge{int to,nxt,dis;}e[M<<];
int cnt=,head[M]={};bool inv[N]={false};
int num=,vid[M],id[N]={},fa[M]={};
int top=,st[M];bool choose[N]={false};
int dis[M][M];bool inq[M]={false};
ll pre[N]={},suf[N]={},p[N]={},s[N]={};
int sz[N]={},len[M],vis[N]={};
int ql,qr,q[N];
inline void link(int u,int v,int w){
e[++cnt]=(edge){v,head[u],w};
head[u]=cnt;
e[++cnt]=(edge){u,head[v],w};
head[v]=cnt;
return;
}
void build(){
for(int i=;i<=m;i++)
if(!ot::tag[i]){
choose[ot::e[i].to]=true;
choose[ot::e[m+i].to]=true;
}
vid[id[st[++top]=]=++num]=;
for(int i=;i<=n;i++){
int x=ot::cur[i];
if(!choose[x])
continue;
int pre=ot::lca(x,st[top]);
for(;top>&&ot::t[st[top-]].dep>=ot::t[pre].dep;top--){
link(id[st[top]],id[st[top-]],ot::t[st[top]].dep-ot::t[st[top-]].dep);
fa[id[st[top]]]=id[st[top-]];
}
if(st[top]!=pre){
link(id[st[top]],id[pre]=++num,ot::t[st[top]].dep-ot::t[pre].dep);
fa[id[st[top]]]=id[pre];vid[num]=st[top]=pre;
}
vid[id[st[++top]=x]=++num]=x;
}
for(int i=top;i>;i--){
link(id[st[i]],id[st[i-]],ot::t[st[i]].dep-ot::t[st[i-]].dep);
fa[id[st[i]]]=id[st[i-]];
}
for(int i=;i<=m;i++)
if(!ot::tag[i])
link(id[ot::e[i].to],id[ot::e[m+i].to],);
return;
}
void spfa(){
memset(dis,0x3f,sizeof(dis));
for(int x=;x<=num;x++){
q[ql=qr=]=x;dis[x][x]=;inq[x]=true;
while(ql<=qr){
int u=q[ql++];inq[u]=false;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(dis[x][v]>dis[x][u]+e[i].dis){
dis[x][v]=dis[x][u]+e[i].dis;
if(!inq[v])
inq[q[++qr]=v]=true;
}
}
}
}
return;
}
void solve(){
for(int i=;i<=num;i++)
for(int u=vid[i];u!=vid[fa[i]];u=ot::t[u].fa[])
inv[u]=true;
inv[]=true;
for(int u=;u<=n;u++){
if(!inv[u])
continue;
sz[u]=;
for(int i=ot::head[u];i;i=ot::e[i].nxt){
int v=ot::e[i].to,pos=ot::t[v].sz;
if(inv[v])
continue;
ans+=(ll)pos*(n-pos);sz[u]+=pos;
ot::solve(v);
}
}
for(int i=;i<=num;i++)
len[i]=ot::t[vid[i]].dep-ot::t[vid[fa[i]]].dep-;
for(int x=;x<=num;x++){
if(!len[x])continue;
pre[len[x]+]=p[len[x]+]=suf[len[x]+]=s[len[x]+]=;
for(int i=,u=ot::t[vid[x]].fa[];i<=len[x];i++,u=ot::t[u].fa[])
pre[i]=pre[i-]+(ll)i*sz[u],p[i]=p[i-]+sz[u];
for(int i=,u=ot::t[vid[x]].fa[];i<=len[x];i++,u=ot::t[u].fa[])
suf[i]=(ll)(len[x]-i+)*sz[u],s[i]=sz[u];
for(int i=len[x]-;i;i--)
suf[i]+=suf[i+],s[i]+=s[i+];
int dist=dis[x][fa[x]],dep1=ot::t[vid[x]].dep;ll val=;
for(int u=ot::t[vid[x]].fa[];u!=vid[fa[x]];u=ot::t[u].fa[]){
int now=dep1-ot::t[u].dep,d=min_(now,len[x]-now+);ll res=;
res+=pre[now+d-]-pre[now-]-(p[now+d-]-p[now-])*now;
res+=suf[now-d+]-suf[now+]-(s[now-d+]-s[now+])*(len[x]-now+);
if(now==len[x]-now+){
val+=res*sz[u];
continue;
}
int l=now-d,r=now+d;
if(r==len[x]+){
if(l<=dist+)
res+=suf[]-suf[l+]-(s[]-s[l+])*(len[x]-now+);
else{
int h=(l-dist-)>>,tg=(l-dist-)&;
res+=pre[h+tg]+p[h+tg]*(len[x]-now++dist);
res+=suf[l-dist-h]-suf[l+]-(s[l-dist-h]-s[l+])*(len[x]-now+);
}
}
else{
if(len[x]-r+<=dist+)
res+=pre[len[x]]-pre[r-]-(p[len[x]]-p[r-])*now;
else{
int h=(len[x]-r-dist)>>,tg=(len[x]-r-dist)&;
res+=pre[r+dist+h]-pre[r-]-(p[r+dist+h]-p[r-])*now;
res+=suf[len[x]-h-tg+]+s[len[x]-h-tg+]*(now+dist);
}
}
val+=res*sz[u];
}//point in the same edge
ans+=val>>;
for(int y=;y<x;y++){
int dist1=,dist2=len[y]+;
for(int u=ot::t[vid[y]].fa[];u!=vid[fa[y]];u=ot::t[u].fa[]){
ll val=;dist1++;dist2--;
int dis1=min_(dist1+dis[x][y],dist2+dis[x][fa[y]]);
int dis2=min_(dist1+dis[fa[x]][y],dist2+dis[fa[x]][fa[y]]);
int d=abs(dis1-dis2);
if(d>=len[x]){
if(dis1<=dis2)
ans+=(pre[len[x]]+p[len[x]]*dis1)*sz[u];
else
ans+=(suf[]+s[]*dis2)*sz[u];
continue;
}
int h=(len[x]-d)>>,tg=(len[x]-d)&;
if(dis1<=dis2){
val+=pre[d+h+tg]+p[d+h+tg]*dis1;
val+=suf[len[x]-h+]-suf[len[x]+]+(s[len[x]-h+]-s[len[x]+])*dis2;
}
else{
val+=pre[h+tg]+p[h+tg]*dis1;
val+=suf[len[x]-d-h+]+s[len[x]-d-h+]*dis2;
}
ans+=val*sz[u];
}
}//edge to edge
for(int i=;i<=num;i++){
int dis1=dis[x][i],dis2=dis[fa[x]][i];
int d=abs(dis1-dis2);ll val=;
if(d>=len[x]){
if(dis1<=dis2)
ans+=(pre[len[x]]+p[len[x]]*dis1)*sz[vid[i]];
else
ans+=(suf[]+s[]*dis2)*sz[vid[i]];
continue;
}
int h=(len[x]-d)>>,tg=(len[x]-d)&;
if(dis1<=dis2){
val+=pre[d+h+tg]+p[d+h+tg]*dis1;
val+=suf[len[x]-h+]-suf[len[x]+]+(s[len[x]-h+]-s[len[x]+])*dis2;
}
else{
val+=pre[h+tg]+p[h+tg]*dis1;
val+=suf[len[x]-d-h+]+s[len[x]-d-h+]*dis2;
}
ans+=val*sz[vid[i]];
}//key point to edge
}
for(int i=;i<num;i++)
for(int j=i+;j<=num;j++)
ans+=(ll)sz[vid[i]]*sz[vid[j]]*dis[i][j];
return;
}
}
int main(){
fread(str,,LEN,stdin);
n=rd();m=rd();ot::build();
vt::build();vt::spfa();
vt::solve();
printf("%lld\n",ans);
return ;
}

cf1089d Distance Sum的更多相关文章

  1. Codeforces Round #336 (Div. 2) B. Hamming Distance Sum 计算答案贡献+前缀和

    B. Hamming Distance Sum   Genos needs your help. He was asked to solve the following programming pro ...

  2. Codeforces Round #336 (Div. 2)B. Hamming Distance Sum 前缀和

    B. Hamming Distance Sum 题目连接: http://www.codeforces.com/contest/608/problem/A Description Genos need ...

  3. Codeforces 608B. Hamming Distance Sum 模拟

    B. Hamming Distance Sum time limit per test: 2 seconds memory limit per test:256 megabytes input: st ...

  4. 关于前缀和,A - Hamming Distance Sum

    前缀和思想 Genos needs your help. He was asked to solve the following programming problem by Saitama: The ...

  5. Codefroces B. Hamming Distance Sum

    Genos needs your help. He was asked to solve the following programming problem by Saitama: The lengt ...

  6. Codeforces Round #336 Hamming Distance Sum

    题目: http://codeforces.com/contest/608/problem/B 字符串a和字符串b进行比较,以题目中的第一个样例为例,我刚开始的想法是拿01与00.01.11.11从左 ...

  7. codeforces 336 Div.2 B. Hamming Distance Sum

    题目链接:http://codeforces.com/problemset/problem/608/B 题目意思:给出两个字符串 a 和 b,然后在b中找出跟 a 一样长度的连续子串,每一位进行求相减 ...

  8. Codeforces 608 B. Hamming Distance Sum-前缀和

      B. Hamming Distance Sum   time limit per test 2 seconds memory limit per test 256 megabytes input ...

  9. LeetCode.1184-公交车站之间的距离(Distance Between Bus Stops)

    这是小川的第次更新,第篇原创 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第265题(顺位题号是1184).公交车有n个从0到n-1的车站,形成一个圆圈.我们知道所有相邻车站对之间的 ...

随机推荐

  1. Spring AOP 实现数据库读写分离

    背景 我们一般应用对数据库而言都是"读多写少",也就说对数据库读取数据的压力比较大,有一个思路就是说采用数据库集群的方案, 其中一个是主库,负责写入数据,我们称之为:写库: 其它都 ...

  2. ubuntu 同时安装anaconda2和anaconda3

    说明:先根据Ubuntu预装的python2.7来安装Anaconda2,然后将Anaconda3作为其环境安装在envs文件夹下. 重要提示:有一些软件需要py2.7的环境,比如XX-Net, 最好 ...

  3. 【问题:SSH】win10使用SSH链接服务器时,提示:Host key verification failed

    异常原因:当前连接新建的验证信息与之前保存的验证信息不一致,将原来的验证信息删除就可以了. 1 使用以下命令,清空之前缓存的信息.或者直接打开C:\Users\Nolan\.ssh\known_hos ...

  4. 【Henu ACM Round#20 E】Star

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 找规律. 1,13,37.... 6n(n-1) + 1 [代码] #include <bits/stdc++.h> # ...

  5. COGS——T1588. [USACO FEB04]距离咨询

    http://cogs.pro/cogs/problem/problem.php?pid=1588 ★★   输入文件:dquery.in   输出文件:dquery.out   简单对比时间限制:1 ...

  6. 洛谷 P2083 找人

    P2083 找人 题目背景 无 题目描述 小明要到他的同学家玩,可他只知道他住在某一单元,却不知住在哪个房间.那个单元有N层(1,2……N),每层有M(1,2……M)个房间. 小明会从第一层的某个房间 ...

  7. 用eclipse 检索SVN 上 myEclipse 建的web项后,成java项目解决方法

    用eclipse 检索SVN 上 myEclipse 建的web项后,成java项目解决方法 在网上找了非常多,都无论用. 说添加.project 文件几个属性.但我发现里面都有,在我这里无论什么用. ...

  8. oracle之ROWNUM的查询应用

    1 在ORACLE数据库中,ROWNUM是ORACLE数据库为查询结果加入的一个伪列.起始值为1.经常使用来处理查询结果的分页. 2 因为ROWNUM的特殊性,使用时候一般是分三层: 第一层:先进行查 ...

  9. POJ2485 Highways 【MST】

    Highways Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 22842   Accepted: 10525 Descri ...

  10. 如何测试WCF Rest

    使用SoapUI 1.新建一个rest项目 2.双击上图中的Request1 查询的时候,Method选择post resource的地方要调整到对应的方法 查询的内容是用json格式发送 查询的的结 ...