BZOJ 2599: [IOI2011]Race

来源:互联网 发布:神硕微营销软件怎么样 编辑:程序博客网 时间:2024/05/01 11:37

首先我知道这是一道点分治可以过的题.

开始考虑普通的点分治套路,dis[],deep[],用来记录当前子树中到当前根的边权和和边的条数,用T[x]保存边权和为x时的最小边数

结果发现自己不太清楚怎么处理在同一棵子树的情况

仔细想想只要等这一棵子树已经遍历过了再更新T数组,而不是在遍历的过程中直接更新,就避免了统计同一子树下的点对(写完这句话我意识到我就是个傻13)


#include<cstdio>#include<algorithm>#define N 200005#define M 1000005#define INF 1e9using namespace std;int n,k,top,ans,pre,cnt=1,sum,root,head[N];struct edge{int to,v,next;}e[N*2];struct p{int deep,dis;}d[N];inline int read(){int a=0,f=1;static char c=getchar();while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){a=a*10+c-'0';c=getchar();}return a*f;}inline void add(int x,int y,int v){e[++cnt].next=head[x];head[x]=cnt;e[cnt].to=y,e[cnt].v=v;}int mx[N],son[N],dis[N],mark[N],deep[N],t[M];void getr(int x,int fa){mx[x]=0,son[x]=1;for(int i=head[x];i;i=e[i].next){if(e[i].to==fa||mark[e[i].to]) continue;getr(e[i].to,x);son[x]+=son[e[i].to];mx[x]=max(mx[x],son[e[i].to]);}mx[x]=max(mx[x],sum-son [x]);if(mx[x]<mx[root]) root=x;}void getd(int x,int fa){int p=dis[x];if(p>k) return;d[++top].deep=deep[x],d[top].dis=dis[x];ans=min(ans,deep[x]+t[k-p]);for(int i=head[x];i;i=e[i].next){if(mark[e[i].to]||e[i].to==fa) continue;dis[e[i].to]=dis[x]+e[i].v;deep[e[i].to]=deep[x]+1;if(dis[e[i].to]<=k)getd(e[i].to,x);}}void cal(int x){dis[x]=0,deep[x]=0;top=0,pre=1;for(int i=head[x];i;i=e[i].next){if(!mark[e[i].to]){deep[e[i].to]=1;dis[e[i].to]=e[i].v;getd(e[i].to,x);for(int i=pre;i<=top;++i){int p=d[i].dis;if(p<=k)t[p]=min(t[p],d[i].deep);}pre=top+1;}}for(int i=1;i<=top;++i){int p=d[i].dis;if(p<=k) t[p]=INF;}t[0]=0;}void solve(int x){cal(x);mark[x]=1;for(int i=head[x];i;i=e[i].next){if(mark[e[i].to]) continue;sum=son[e[i].to];root=0;getr(e[i].to,0);solve(root);}}int main(){n=read(),k=read();int i,x,y,v;for(i=1;i<n;++i){x=read(),y=read(),v=read();++x,++y;add(x,y,v),add(y,x,v);}mx[0]=N,sum=n;ans=INF;for(int i=1;i<=k;++i) t[i]=INF;getr(1,0);solve(root);printf("%d\n",ans==INF?-1:ans);return 0;}

原创粉丝点击