洛谷模板题
利用点分治复杂度约为nlogn,再加上其他操作的复杂度。
总结一下:
1. 每次找子树的重心作根递归进行。
2. 注意各种标记vis标记回溯时需去掉。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;//加找重心
struct edge
{
int to,next,w;
edge(int to=0,int next=0,int w=0):to(to),next(next),w(w){}
};
vector<edge> edges;
int head[maxn],cnt=0;
void add_edge(int u,int v,int w)
{
edges.push_back(edge(v,head[u],w));
head[u]=edges.size()-1;
}
int n,m,k[105];
int dis[maxn*1000],ch[maxn],ok[105],vis[maxn],siz[maxn];
int dfs(int s,int f)
{
int child=0,sum=0;
ch[s]=0;
for(int i=head[s];i!=-1;i=edges[i].next)
{
edge e=edges[i];
if(e.to==f||vis[e.to]) continue;
else if(!vis[e.to])
{
int tmp=dfs(e.to,s);
child=max(tmp,child);
sum+=tmp;
}
}
ch[s]=child;
siz[s]=sum+1;
return sum+1;
}
int Core,num;
void getcore(int s,int f,int sz)
{
int core=max(ch[s],sz-siz[s]);
if(core<num)
{
num=core;
Core=s;
}
for(int i=head[s];i!=-1;i=edges[i].next)
{
edge e=edges[i];
if(e.to==f||vis[e.to]) continue;
else
{
getcore(e.to,s,sz);
}
}
}
int tmp[maxn],c=0,mk=0;
void cal(int s,int f,int d,int sign)
{
if(sign==1)
{
if(d>mk) return;
for(int i=1;i<=m;i++)
{
if(k[i]>=d&&dis[k[i]-d]==1) ok[i]=1;
}
tmp[++c]=d;
for(int i=head[s];i!=-1;i=edges[i].next)
{
edge e=edges[i];
if(e.to==f||vis[e.to]) continue;
cal(e.to,s,d+e.w,1);
}
return;
}
else
{
if(d>mk) return;
dis[d]=0;
for(int i=head[s];i!=-1;i=edges[i].next)
{
edge e=edges[i];
if(e.to==f||vis[e.to]) continue;
cal(e.to,s,d+e.w,2);
}
return ;
}
}
void solve(int s,int f)
{
vis[s]=1;
for(int i=head[s];i!=-1;i=edges[i].next)
{
edge e=edges[i];
if(e.to==f||vis[e.to]) continue;
else
{
dfs(e.to,s);
num=maxn;
getcore(e.to,s,siz[e.to]);
solve(Core,0);
}
}
dis[0]=1;
for(int i=head[s];i!=-1;i=edges[i].next)
{
edge e=edges[i];
if(e.to==f||vis[e.to]) continue;
else
{
c=0;
cal(e.to,s,e.w,1);
for(int i=1;i<=c;i++)
{
dis[tmp[i]]=1;
}
}
}
cal(s,f,0,2);
vis[s]=0;
return ;
}
int main()
{
//freopen("tte.txt","r",stdin);
//freopen("out.txt","w",stdout);
memset(head,-1,sizeof(head));
scanf("%d %d",&n,&m);
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
}
for(int i=1;i<=m;i++)
{
scanf("%d",&k[i]);
mk=max(mk,k[i]);
}
dfs(1,0);
num=maxn;
getcore(1,0,siz[1]);
solve(Core,0);
for(int i=1;i<=m;i++)
{
if(ok[i]) printf("AYE\n");
else printf("NAY\n");
}
}
简化:
1求重心代码只需一段(来自洛谷题解)
void find(int x,int fa)
{
size[x] = 1; mx[x] = 0;
for (int i = head[x]; i ; i = edges[i].net)
{
edge v = edges[i];
if(v.to == fa||vis[v.to] ) continue;//vis是之后分治是要用到的
find(v.to,x);
size[x] += size[v.to];
chkmax(mx[x],size[v.to]);
}
chkmax(mx[x],S-size[x]);//S为树的大小,记住x的上面要算入的
if(mx[x] < mx[root])
{
root = x;
}
}