CF1060E Sergey and Subway(点分治)
给出一颗$N$个节点的树,现在我们**在原图中**每个不直接连边但是中间只间隔一个点的两个点之间连一条边. 比如**在原图中**$u$与$v$连边,$v$与$w$连边,但是$u$与$w$不连边,这时候我们就需要连一条$u$与$v$的边. 现在我们需要求出新图中每一个点对$(i,j)\ (1 \leq i \leq j \leq N)$的经过的边数和.
因为实在太菜了不会树形dp的只好用点分了……
(点分是个好东西所有树的题目都可以暴力艹过去)
首先,设原点对之间距离为$dis$,如果$dis$是奇数,那么新的距离为$(dis>>1)+1$,否则为$dis>>1$
我们考虑如何计算经过当前根节点的路径对答案的贡献
我们设已经dfs过的子树中有$cnt0$条长度为偶数的链,$dis0$这些链的每一条的长度除以二之和,同理$cnt1$和$dis1$表示长度为奇数的链的条数和每一条链的长度除以二加一的和
简单来讲$dis1$和$dis0$分别表示将原$dis$按上面的方法转化后的答案
然后考虑当前子树$v$,设$v$中的以上信息分别为,$cnt[0],cnt[1],dis[0],dis[1]$
然后就是路径的两两组合分别计入答案就是了
顺便注意因为两条奇数路径合起来变为偶数,所以相当于每一条路径的长度都要减一
然后别忘了加上子树单独的贡献
//minamoto
#include<bits/stdc++.h>
#define ll long long
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,:;}
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
const int N=2e5+;
int head[N],Next[N<<],ver[N<<],tot;
int cnt[];ll dis[],ans=;
inline void add(int u,int v){
ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
}
int sz[N],son[N],size,vis[N],rt,n;
void findrt(int u,int fa){
sz[u]=,son[u]=;
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(vis[v]||v==fa) continue;
findrt(v,u),sz[u]+=sz[v],cmax(son[u],sz[v]);
}
cmax(son[u],size-sz[u]);
if(son[u]<son[rt]) rt=u;
}
void dfs(int u,int fa,int d){
d&?(++cnt[],dis[]+=((d>>)+)):(++cnt[],dis[]+=(d>>));
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(v!=fa&&!vis[v]) dfs(v,u,d+);
}
}
void getans(int u){
int cnt0=,cnt1=;ll dis0=,dis1=;
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(vis[v]) continue;
cnt[]=cnt[]=,dis[]=dis[]=;
dfs(v,u,);
// ans+=dis[1]*dis1-cnt[1]*cnt1;
// ans+=dis[1]*dis0;
// ans+=dis[0]*dis1;
// ans+=dis[0]*dis0;
ans+=dis[]*cnt1+dis1*cnt[]-1ll*cnt1*cnt[];
ans+=dis[]*cnt0+dis0*cnt[];
ans+=dis[]*cnt1+dis1*cnt[];
ans+=dis[]*cnt0+dis0*cnt[];
ans+=dis[]+dis[];
cnt0+=cnt[],cnt1+=cnt[];
dis0+=dis[],dis1+=dis[];
}
}
void solve(int u){
vis[u]=,getans(u);
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(vis[v]) continue;
size=sz[v],rt=,findrt(v,u);
solve(rt);
}
}
int main(){
// freopen("testdata.in","r",stdin);
n=read();
for(int i=,u,v;i<n;++i)
u=read(),v=read(),add(u,v),add(v,u);
son[rt=]=n+,size=n,findrt(,);
solve(rt);
printf("%I64d\n",ans);
return ;
}
CF1060E Sergey and Subway(点分治)的更多相关文章
- [CF1060E]Sergey and Subway[树dp]
题意 给出 \(n\) 个点的树,求 \(\sum_{i=1}^n{\sum_{j=i}^n{\lceil \frac{dis(i,j)}{2} \rceil}}\) . \(n\leq 2 \tim ...
- CF1060E Sergey and Subway 思维
分两种情况讨论 一种为奇数长为$L$的路径,在经过变化后,我们需要走$\frac{L}{2} + 1$步 一种为偶数长为$L$的路径,在变化后,我们需要走$\frac{L}{2}$步 那么,我们只需要 ...
- cf1060E. Sergey and Subway(树形dp)
题意 题目链接 Sol 很套路的题 直接考虑每个边的贡献,最后再把奇数点的贡献算上 #include<bits/stdc++.h> #define Pair pair<int, in ...
- CF1060E Sergey and Subways 假的点分治
题目传送门:http://codeforces.com/problemset/problem/1060/D 题意:给出$N$个点的一棵树,现在将距离为$2$的点之间连一条边,求所有点对之间最短路的和, ...
- 1060E Sergey and Subway(思维题,dfs)
题意:给出一颗树,现在,给哪些距离为2的点对,加上一条边,问所有点对的距离和 题解:如果没有加入新的边,距离和就会等于每条边的贡献,由于是树,我们用点来代表点上面的边,对于每条边,它的贡献将是(子树大 ...
- CF 1060E. Sergey and Subway
题目链接 题意:给你一棵树,然后连接两个有公共邻居的点,问你连完后,任意两点的距离之和. 一开始看这种题,还不怎么会做,借鉴了这位大佬的博客,get到了新技能,当我们求树上任意俩点的距离之时,可以转化 ...
- E. Sergey and Subway
比赛时候写复杂了…… 我写的是 计算每个节点树内所有点到某个点的距离和. #include <bits/stdc++.h> using namespace std; typedef lon ...
- 【非原创】codeforces 1060E Sergey and Subway 【树上任意两点距离和】
学习博客:戳这里 本人代码: 1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 con ...
- Codeforces Round #513 游记
Codeforces Round #513 游记 A - Phone Numbers 题目大意: 电话号码是8开头的\(1\)位数字.告诉你\(n(n\le100)\)个数字,每个数字至多使用一次.问 ...
随机推荐
- java中等待所有线程都执行结束(转)
转自:http://blog.csdn.net/liweisnake/article/details/12966761 今天看到一篇文章,是关于java中如何等待所有线程都执行结束,文章总结得很好,原 ...
- iGrimaceVX3.0和1.44在线源手机直接安装教程
[第一步] 先安装好三个组件设备必须是苹果越狱好后 确定6点几跟7点几的版本号才干够 首先打开cydia 选开发人员 以下 点软件源 点右上角编辑 1加入源 apt.25pp.com和IG包下载源a ...
- 使网页适应UIWebView的宽度
比較简单的做法是:在- (void)webViewDidFinishLoad:这种方法中,改动JavaScript的值: //UIWebViewDelegate - (void)webViewDidF ...
- HDOJ1004 数组还要自己初始化
#include <iostream> #include <stdio.h> #include "string.h"using namespace std; ...
- 例子:两个表根据productID合并
- 使用Mock.js进行独立于后端的前端开发
Mockjs能做什么? 基于 数据模板 生成模拟数据. 基于 HTML模板 生成模拟数据. 拦截并模拟 ajax 请求. 能解决的问题 开发时,前后端进度不同步,后端还没完成数据输出,前端只好写静态模 ...
- POJ1144 Network 无向图割点
题目大意:求以无向图割点. 定义:在一个连通图中,如果把点v去掉,该连通图便分成了几个部分,则v是该连通图的割点. 求法:如果v是割点,如果u不是根节点,则u后接的边中存在割边(u,v),或者v-&g ...
- UISegmentedControl方法与属性的总结
SegmentedControl又被称作分段控制器,是IOS开发中经常用到的一个UI控件. 初始化方法:传入的数组可以是字符串也可以是UIImage对象的图片数组 - (instancetype)in ...
- gson如何转化json数组
String.JsonObject.JavaBean 互相转换 User user = new Gson().fromJson(jsonObject, User.class); User user = ...
- HDU 5666 Segment
Segment Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Sub ...