链接:https://codeforces.com/contest/161/problem/D

题意:给一个树,求距离恰好为$k$的点对是多少

题解:对于一个树,距离为$k$的点对要么经过根节点,要么跨过子树的根节点,于是考虑树分治

用类似poj1741的想法,可以推出:

对于任意一棵子树,其根节点记为$C$,其子树中:

记距离$C$距离之和为$k$的点对数量$S_{c}$

记$C$儿子节点$C_1...C_n$的子树中,距离$C_i$距离为$k-2$的点对数量为$S'_{c_i}$

其符合条件的点对数量即为$S_{c}-\sum_1^n S'_{c_i}$

(网上这题,主流的树分治写法好像不是这个...有些看不懂啊....)

树上点分治参考我之前的题解:https://www.cnblogs.com/nervendnig/p/10106333.html

速度还是很可以的

相比dp的话,dp收到$K$大小的限制,如果$K$的大小和N同级别,就很难朴素的DP了,可能就要考虑树上倍增DP(实际上好像不能倍增)

而分治显然并不受限制

具体参见代码:

#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define fi first
#define se second
#define mp make_pair
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define IO ios::sync_with_stdio(false)
#define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
#define per(ii,a,b) for(int ii=b;ii>=a;--ii)
#define forn(x,i) for(int i=head[x];i;i=e[i].next)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#define inline inline __attribute__( \
(always_inline, __gnu_inline__, __artificial__)) \
__attribute__((optimize("Ofast"))) __attribute__((target("sse"))) __attribute__((target("sse2"))) __attribute__((target("mmx")))
using namespace std;
#define tpyeinput int
char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;}
void read(tpyeinput &sum) {register char ch=nc();int flag=1;sum=0;while(ch<'0'||ch>'9') {if(ch=='-') flag=-1;ch=nc();}while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();sum*=flag;}
void read(tpyeinput &num1,tpyeinput &num2) {read(num1);read(num2);}
const int maxn=1e5+10,maxm=2e5+10;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
const double PI=acos(-1.0);
//head
int casn,n,m,k,mid,allnode;
struct node {int to,next;}e[maxm];int head[maxn],nume;
void add(int a,int b){e[++nume]=(node){b,head[a]};head[a]=nume;}
int sz[maxn],maxt,deep[maxn],vis[maxn],cnt;
ll ans;
void getc(int now,int pre){
sz[now]=1;
for(int i=head[now];i;i=e[i].next){
if(e[i].to==pre||vis[e[i].to])continue;
getc(e[i].to,now);
sz[now]+=sz[e[i].to];
}
int tmp=max(sz[now]-1,allnode-sz[now]);
if(maxt>tmp) maxt=tmp,mid=now;
}
void dfs(int now,int pre,int len,int dis){
deep[++cnt]=dis;
if(dis>=len)return;
for(int i=head[now];i;i=e[i].next){
if(e[i].to==pre||vis[e[i].to])continue;
dfs(e[i].to,now,len,dis+1);
}
}
ll cal(int rt,int pre,int len){
if(len<=0) return len==0;
cnt=0;
dfs(rt,pre,len,0);
ll res=0;
int num[507]{};
rep(i,1,cnt) num[deep[i]]++;
rep(i,1,cnt) res+=num[len-deep[i]];
return res;
}
void dc(int rt){
vis[rt]=1;
ans+=cal(rt,0,k);
for(int i=head[rt];i;i=e[i].next){
if(vis[e[i].to]) continue;
ans-=cal(e[i].to,rt,k-2);
allnode=sz[e[i].to],maxt=n;
getc(e[i].to,rt);dc(mid);
}
}
int main() {
//#define test
#ifdef test
auto _start = chrono::high_resolution_clock::now();
freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
#endif
read(n,k);
int a,b;
rep(i,1,n-1){
read(a,b);
add(a,b);add(b,a);
}
allnode=n;
maxt=INF;
getc(1,0);
dc(mid);
printf("%lld",ans/2);
#ifdef test
auto _end = chrono::high_resolution_clock::now();
cerr << "elapsed time: " << chrono::duration<double, milli>(_end - _start).count() << " ms\n";
fclose(stdin);fclose(stdout);system("out.txt");
#endif
return 0;
}

  

codeforces 161D Distance in Tree 树上点分治的更多相关文章

  1. codeforces 161D Distance in Tree 树形dp

    题目链接: http://codeforces.com/contest/161/problem/D D. Distance in Tree time limit per test 3 secondsm ...

  2. Codeforces 161D Distance in Tree(树型DP)

    题目链接 Distance in Tree $k <= 500$ 这个条件十分重要. 设$f[i][j]$为以$i$为子树,所有后代中相对深度为$j$的结点个数. 状态转移的时候,一个结点的信息 ...

  3. Codeforces 161D Distance in Tree(树的点分治)

    题目大概是,给一棵树,统计距离为k的点对数. 不会DP啊..点分治的思路比较直观,啪啪啪敲完然后AC了.具体来说是这样的: 树上任何两点的路径都可以看成是一条过某棵子树根的路径,即任何一条路径都可以由 ...

  4. Codeforces 161D Distance in Tree

    题目大意:给出一棵n个节点的树,统计树中长度为k的路径的条数(1<=n<=50000 , 1<=k<=500) 思路:树分治! #include<cstdio> # ...

  5. CodeForces 161D Distance in Tree【树形DP】

    <题目链接> 题目大意:一颗无向无环树,有n个顶点,求其中距离为k的点对数是多少,(u,v)与(v,u)为同一点对. #include <cstdio> #include &l ...

  6. POJ 1741 Tree 树上点分治

    题目链接:http://poj.org/problem?id=1741 题意: 给定一棵包含$n$个点的带边权树,求距离小于等于K的点对数量 题解: 显然,枚举所有点的子树可以获得答案,但是朴素发$O ...

  7. CodeForces161D: Distance in Tree(树分治)

    A tree is a connected graph that doesn't contain any cycles. The distance between two vertices of a ...

  8. 【Codeforces 715C】Digit Tree(点分治)

    Description 程序员 ZS 有一棵树,它可以表示为 \(n\) 个顶点的无向连通图,顶点编号从 \(0\) 到 \(n-1\),它们之间有 \(n-1\) 条边.每条边上都有一个非零的数字. ...

  9. CF 161D Distance in Tree 树形DP

    一棵树,边长都是1,问这棵树有多少点对的距离刚好为k 令tree(i)表示以i为根的子树 dp[i][j][1]:在tree(i)中,经过节点i,长度为j,其中一个端点为i的路径的个数dp[i][j] ...

随机推荐

  1. mysql错误汇集

    [Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated.. ...

  2. C#设计模式(14)——模板方法模式

    1.模板方法模式介绍 提到模板我们经常会想到简历模板/PPT模板等,以简历模板为例,不同的人可以使用一样的简历模板,在填充内容时根据自己的名字/工作经历等填写自己的内容,从而形成不同的简历.在OO中模 ...

  3. Chrome Dev Tools: Code Folding in CSS and Javascript for improved code readiability

    Note : Apply for google chrome canary. You can fold code blocks in CSS (and Sass) and javascript fil ...

  4. HDU 6362(求椭圆中矩形周长的期望 数学)

    题意是给定一个椭圆标准方程的a,b(椭圆的长半轴长和短半轴长),在[0,b]内取一个数,则过点(0,b)且平行于x轴的直线与椭圆交于两点,再将此两点关于x轴做对称点,顺次连接此四点构成矩形,求出这些矩 ...

  5. scoketserver模块(TCP协议 与 udp 协议)

    socketserver模块 ( 基于 TCP 协议 ) import socketserver # 自定义类用来处理通信循环 class MyTCPhanler(socketserver.BaseR ...

  6. vue中computed和watch

    computed 计算属性 能够监听vue数据上的变化,页面上来就执行一次,每改变一次数据就又触发.在操作数据的时候,会派生出另一个事情 1.函数形式 computed:{ listenArr(){ ...

  7. vue实现简单的全选、反选、不选

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. Java爬网页数据,并存储到本地数据库中

    由于开发一个人工智能项目,需要强大的后台数据库加持,所以,没有办法,又是需要医疗数据,只能自己爬某医疗网站数据,进行分析,但是由于不同网站的结构不一样,所以这个程序只能爬该网站的,第一次爬网页数据,自 ...

  9. 【SRM-07 D】天才麻将少女KPM

    Description 天才麻将少女KPM立志要在日麻界闯出一番名堂.KPM上周叒打了n场麻将,但她这次又没控分,而且因为是全市参与的麻将大赛,所以她的名次范围是0..10^5.名次可能等于0是因为K ...

  10. PHP中的会话控制—session和cookie(实现数据传值功能)

    1.session  登录上一个页面以后,长时间没有操作,刷新页面以后需要重新登录. 特点:(1)session是存储在服务器:   (2)session每个人(登陆者)存一份: (3)session ...