【bzoj2599】[IOI2011]Race 点分治

来源:互联网 发布:mousewheel.js api 编辑:程序博客网 时间:2024/05/16 15:48
点分治
1、求树的重心
2、计算以当前重心为根的子树的答案
3、去掉以当前重心儿子为根的子树的答案
4、枚举每个儿子,分治

考虑计算过程如何实现
我们不妨记一个ans数组,ans[i]表示使用i条边权值为k的有多少对
每次实现2的时候,权值设为+1
每次实现3的时候,权值设为-1

把子树内所有的dis排序,计算有多少对权值和为k的,两个指针扫一遍就可以了。


#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<algorithm>#include<iostream>#define maxn 200100 using namespace std;struct yts{int d1,d2;}st[maxn];int head[maxn],to[2*maxn],next[2*maxn],len[2*maxn],dis[maxn],dep[maxn];int size[maxn],ans[maxn],fa[maxn];bool vis[maxn];int n,m,num,k,top;bool cmp(yts x,yts y){return x.d1<y.d1;}void addedge(int x,int y,int z){num++;to[num]=y;len[num]=z;next[num]=head[x];head[x]=num;}void get_root(int x,int Size,int &cg){bool flag=1;size[x]=1;for (int p=head[x];p;p=next[p])  if (!vis[to[p]] && to[p]!=fa[x])  {  fa[to[p]]=x;  get_root(to[p],Size,cg);  size[x]+=size[to[p]];  if (size[to[p]]>Size/2) flag=0;  }if (Size-size[x]>Size/2) flag=0;if (flag) cg=x;}void dfs1(int x,int d1,int d2){dis[x]=d1;dep[x]=d2;for (int p=head[x];p;p=next[p])  if (!vis[to[p]] && to[p]!=fa[x]) fa[to[p]]=x,dfs1(to[p],d1+len[p],d2+1);}void dfs2(int x){st[++top].d1=dis[x];st[top].d2=dep[x];for (int p=head[x];p;p=next[p])  if (!vis[to[p]] && to[p]!=fa[x]) dfs2(to[p]);}void calc(int x,int f){top=0;dfs2(x);sort(st+1,st+top+1,cmp);for (int i=1,j=top;i<=j;i++){while (j>i && st[i].d1+st[j].d1>k) j--;for (int p=j;st[i].d1+st[p].d1==k;p--) ans[st[i].d2+st[p].d2]+=f;}}void solve(int x,int Size){int cg;fa[x]=0;get_root(x,Size,cg);size[fa[cg]]=Size-size[cg];fa[cg]=0;vis[cg]=1;dfs1(cg,0,0);calc(cg,1);for (int p=head[cg];p;p=next[p]) if (!vis[to[p]]) calc(to[p],-1);for (int p=head[cg];p;p=next[p]) if (!vis[to[p]]) solve(to[p],size[to[p]]);}int main(){scanf("%d%d",&n,&k);for (int i=1;i<n;i++){int x,y,z;scanf("%d%d%d",&x,&y,&z);x++;y++;addedge(x,y,z);addedge(y,x,z);}solve(1,n);for (int i=1;i<n;i++) if (ans[i]) {printf("%d\n",i);return 0;}printf("-1\n");return 0;}


0 0