【BZOJ 2599】 [IOI2011]Race 树的点分治

来源:互联网 发布:手写电子笔记软件 编辑:程序博客网 时间:2024/05/18 00:56

还是比较简单的树分治了吧(居然是ioi的题目,好开森qwq)。

众所周知,在树分治的过程中是会有重复计算的,因此我们每一次处理当前子树的时候都会减去子树的影响,所以定义ans[i]数组表示经过i条边,距离长度为k的点对数,这样就可以++或者--来维护这个ans数组了,然后就没什么了

吐槽:难道同一个点到一个点再走回来是合法吗?为毛要while(l<=r)wa了几发

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define maxn 200020using namespace std;int n,cnt,m,k,vis[maxn],head[maxn],h[maxn],tot,s[maxn],size,dis[maxn],rt,ans[maxn],f[maxn];struct edge{int v,next,w;}e[maxn*2];void adde(int a,int b,int c){e[tot].v=b,e[tot].w=c,e[tot].next=head[a];head[a]=tot++;}struct data{int d,h;data(int a=0,int b=0):d(a),h(b){}bool operator<(const data& b)const {return d<b.d;}}q[maxn];void getrt(int u,int fa){f[u]=0,s[u]=1;for(int i=head[u],v;i!=-1;i=e[i].next){if(vis[v=e[i].v]||v==fa)continue;getrt(v,u);s[u]+=s[v];f[u]=max(s[v],f[u]);}f[u]=max(f[u],size-f[u]);if(f[u]<f[rt])rt=u;}//计算两点之间的距离等于k void dfs(int u,int fa){if(dis[u]>k)return;q[++cnt]=data(dis[u],h[u]);for(int i=head[u],v;i!=-1;i=e[i].next ){if(vis[v=e[i].v]||v==fa)continue;dis[v]=dis[u]+e[i].w,h[v]=h[u]+1;dfs(v,u);}}void calc(int u,int d1,int h1,int pos){dis[u]=d1,h[u]=h1,cnt=0;dfs(u,u);sort(q+1,q+1+cnt);int l=1,r=cnt;while(l<=r){while(l<r&&q[l].d+q[r].d>k)r--;for(int t=r;q[l].d+q[t].d==k;t--)ans[q[l].h+q[t].h]+=pos;l++;}}void solve(int u){vis[u]=1;calc(u,0,0,1);for(int i=head[u],v;i!=-1;i=e[i].next ){if(vis[v=e[i].v])continue;calc(v,e[i].w,1,-1);f[rt=0]=size=s[v];getrt(v,u);solve(rt);}}int main(){scanf("%d%d",&n,&k);memset(head,-1,sizeof(head));for(int a,b,c,i=1;i<n;i++){scanf("%d%d%d",&a,&b,&c);a++,b++;adde(a,b,c),adde(b,a,c);}size=n,f[rt=0]=size;getrt(1,0);solve(rt);for(int i=1;i<=n;i++)if(ans[i]>0){printf("%d",i);return 0;}puts("-1");return 0;}


0 0
原创粉丝点击