不会点分治的我瑟瑟发抖
点分治:对树进行的一种分层操作。
这种算法的均摊的复杂度是:log
这种算法和树链剖分的区别是
1)树链剖分可以解决待修改问题
2)点分治是解决计数类和全树路径的问题,树链剖分的路径是特殊的
好的我们看一下点分治:
例题:
树中点对统计
这个有~困难
记录某个部分的所有路径然后暴力匹配
这里有个减贡献的问题
这个实际上会被计算是吧QwQ
所以特别减掉这个贡献
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=1e5+100;
struct Front_star{
int u,v,w,nxt;
}e[N<<2];
int cnt=0;
int first[N];
void add(int u,int v,int w){
++cnt;
e[cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
e[cnt].nxt=first[u];
first[u]=cnt;
}
//
int ans=0;
int n,K;
int All;
int root;
int siz[N];
int vis[N];
int F[N];
void Get_Root(int u,int fat){
int now=0;
siz[u]=1;
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].v;
if(v==fat||vis[v])continue;
Get_Root(v,u);
siz[u]+=siz[v];
if(now<siz[v])now=siz[v];
}
// cout<<u<<" "<<now<<'\n';
if(now<All-siz[u])now=All-siz[u];
F[u]=now;
if(F[root]>now)root=u;
}
int deep[N];
int d[N];
void Get_Deep(int u,int fat){
deep[++deep[0]]=d[u];
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].v;
if(vis[v]||v==fat)continue;
d[v]=d[u]+e[i].w;
Get_Deep(v,u);
}
}
int Solve(int u,int dep){
d[u]=dep;
deep[0]=0;
Get_Deep(u,0);
sort(deep+1,deep+1+deep[0]);
int ret=0;
for(int l=1,r=deep[0];l<r;){
if(deep[l]+deep[r]<=K){
ret+=r-l;
l++;
}
else r--;
}
return ret;
}
void DFS(int u){
vis[u]=1;
ans+=Solve(u,0);
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].v;
if(vis[v])continue;
ans-=Solve(v,e[i].w);
All=siz[v];
root=0;
Get_Root(v,0);
DFS(root);
}
}
int main(){
// freopen("test.in","r",stdin);
F[0]=1e9+7;
scanf("%d%d",&n,&K);
for(int i=1;i<n;++i){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
root=0;
All=n;
Get_Root(1,0);
DFS(root);
cout<<ans;
}