求树上最小距离等于K的点对是否存在
离线+点分治
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e4+5;
const int INF=1e7;
int n,m,K;
struct P
{
int to,nxt,v;
void is(int x1,int x2,int x3){to=x1;nxt=x2;v=x3;}
}e[MAX<<1];
int head[MAX],sz[MAX],dis[MAX],maxp[MAX],rem[MAX],test[MAX],query[MAX],judge[INF],q[MAX],cnt,sum,rt;
bool vis[MAX];
void init()
{
cnt=0;
memset(head,-1,sizeof(head));
}
void adde(int u,int v,int w)
{
e[cnt].is(v,head[u],w);head[u]=cnt++;
e[cnt].is(u,head[v],w);head[v]=cnt++;
}
void getrt(int u,int pa)
{
sz[u]=1; maxp[u]=0;
for(int i=head[u];i!=-1;i=e[i].nxt)
{
int to=e[i].to;
if(to==pa||vis[to]) continue;
getrt(to,u);
sz[u]+=sz[to];//update the number of subnode in root [u],[to] is [u]‘s subnode
maxp[u]=max(maxp[u],sz[to]);//update the max of root [u],if sz [to] is greater
}
maxp[u]=max(maxp[u],sum-sz[u]);//in_ex
if(maxp[u]<maxp[rt]) rt=u;
}
void getdis(int u,int fa)
{
rem[++rem[0]]=dis[u];
for(int i=head[u];i!=-1;i=e[i].nxt)
{
int to=e[i].to;
if(to==fa||vis[to])continue;
dis[to]=dis[u]+e[i].v;
getdis(to,u);
}
}
void calc(int u)
{
int p=0;
for(int i=head[u];i!=-1;i=e[i].nxt)
{
int to=e[i].to;
if(vis[to])continue;
rem[0]=0; dis[to]=e[i].v;
getdis(to,u);//处理u的每个子树的dis
for(int j=rem[0];j;--j)//遍历当前子树的dis
for(int k=1;k<=m;++k)//遍历每个询问
if(query[k]>=rem[j])
test[k]|=judge[query[k]-rem[j]];
//如果query[k]-rem[j]d的路径存在就标记第k个询问
for(int j=rem[0];j;--j)//保存出现过的dis于judge
q[++p]=rem[j],judge[rem[j]]=1;
}
for(int i=1;i<=p;++i)//处理完这个子树就清空judge
judge[q[i]]=0;//特别注意一定不要用memeset,会T
}
void divide(int u)
{
//judge[i]表示到根距离为i的路径是否存在
vis[u]=1;judge[0]=1; calc(u);//处理以u为根的子树
for(int i=head[u];i!=-1;i=e[i].nxt)//对每个子树进行分治
{
int to=e[i].to;
if(vis[to])continue;
sum=sz[to]; maxp[rt=0]=INF;
getrt(to,0); divide(rt);//在子树中找重心并递归处理
}
}
int main()
{
int x,y,z;
init();
scanf("%d%d",&n,&m);
for(int i=1;i<n;++i)
{
scanf("%d%d%d",&x,&y,&z);
adde(x,y,z);
}
for(int i=1;i<=m;++i)scanf("%d",&query[i]);
maxp[rt]=sum=n;
getrt(1,0);
divide(rt);
for(int i=1;i<=m;++i) printf("%s\n",test[i]?"AYE":"NAY");
return 0;
}
求树上最小距离小于m的点对个数
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAX=1e4+5;
int n,m;
struct P
{
int to,nxt,v;
void is(int x1,int x2,int x3){to=x1;nxt=x2;v=x3;}
}e[MAX<<1];
int head[MAX],sz[MAX],dis[MAX],maxp[MAX],rem[MAX],cnt,sum,rt,ans;
bool vis[MAX];
void init()
{
cnt=ans=rt=0;rem[0]=0;
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
}
void adde(int u,int v,int w)
{
e[cnt].is(v,head[u],w);head[u]=cnt++;
e[cnt].is(u,head[v],w);head[v]=cnt++;
}
void getrt(int u,int pa)
{
sz[u]=1; maxp[u]=0;
for(int i=head[u];i!=-1;i=e[i].nxt)
{
int to=e[i].to;
if(to==pa||vis[to]) continue;
getrt(to,u);
sz[u]+=sz[to];//update the number of subnode in root [u],[to] is [u]‘s subnode
maxp[u]=max(maxp[u],sz[to]);//update the max of root [u],if sz [to] is greater
}
maxp[u]=max(maxp[u],sum-sz[u]);//in_ex
if(maxp[u]<maxp[rt]) rt=u;
}
void getdis(int u,int fa)
{
rem[++rem[0]]=dis[u];
for(int i=head[u];i!=-1;i=e[i].nxt)
{
int to=e[i].to;
if(to==fa||vis[to])continue;
dis[to]=dis[u]+e[i].v;
getdis(to,u);
}
}
int cal(int u,int ct)
{
dis[u]=ct;rem[0]=0;
getdis(u,0);
sort(rem+1,rem+rem[0]+1);
int l=1,r=rem[0],x=0;
while(l<r)
{
if(rem[l]+rem[r]<=m) {x+=r-l;++l;}
else --r;
}
return x;
}
int divide(int u)
{
vis[u]=1;ans+=cal(u,0);//处理以u为根的子树
for(int i=head[u];i!=-1;i=e[i].nxt)//对每个子树进行分治
{
int to=e[i].to;
if(vis[to])continue;
ans-=cal(to,e[i].v);
sum=sz[to];rt=0;
getrt(to,0); divide(rt);//在子树中找重心并递归处理
}
return ans;
}
int main()
{
int x,y,z;
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0) break;
init();
for(int i=1;i<n;++i)
{
scanf("%d%d%d",&x,&y,&z);
adde(x,y,z);
}
maxp[rt]=sum=n;
getrt(1,0);
printf("%d\n",divide(rt));
}
return 0;
}
求点对最小距离等于m 的数量
int cal_(int u,int ct)
{
dis[u]=ct;rem[0]=0;
getdis(u,0);
sort(rem+1,rem+rem[0]+1);
int r=rem[0],x=0;
for(int l=1;l<r;++l)
{
while(rem[l]+rem[r]==m) ++x;
--r;
}
return x;
}