点分治[BZOJ]2599: [IOI2011]Race

来源:互联网 发布:ubuntu切换到windows 编辑:程序博客网 时间:2024/05/17 23:31

题目:给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000

思路:先找到根,然后求出经过根的路径数最小的方案。在处理一个节点时,用已处理的信息加上当前点的信息来更新答案,t[i]表示距离根为i的节点的最小深度,dis[i]表示i节点离根的距离,ans=min(ans,t[k-dis[i]]+d[i])。处理完根的一个子树后再更新一下信息,可以保证答案经过根。对每个子树分治一下就好了。

#include <cstdio>#include <vector>using namespace std;inline char tc(void){    static char fl[1000000],*A=fl,*B=fl;    return A==B&&(B=(A=fl)+fread(fl,1,1000000,stdin),A==B)?EOF:*A++;}inline int read(void){    int a=0;static char c;    while((c=tc())<'0'||c>'9');    while(c>='0'&&c<='9')        a=a*10+c-'0',c=tc();    return a;}struct Edge{    int to,cost;    Edge(int t,int c):to(t),cost(c){}};int n,k,t[1000001],mx[200001],size[200001],d[200001],dis[200001],sum,root,ans=1e9;char vis[200001];vector<Edge>edge[200001];void dfs1(int x,int fa){    register int i;    size[x]=1,mx[x]=0;    for (i=0;i<edge[x].size();++i)        if(!vis[edge[x][i].to]&&edge[x][i].to!=fa)            dfs1(edge[x][i].to,x),mx[x]=max(mx[x],size[edge[x][i].to]),size[x]+=size[edge[x][i].to];    mx[x]=max(mx[x],sum-size[x]);mx[x]<mx[root]?root=x:0;    return ;}void add(int x,int fa,int flag) {    register int i;    flag?t[dis[x]]=min(t[dis[x]],d[x]):t[dis[x]]=1e9;    for (i=0;i<edge[x].size();++i)        if(!vis[edge[x][i].to]&&edge[x][i].to!=fa&&dis[edge[x][i].to]<=k)            add(edge[x][i].to,x,flag);    return ;}void cal(int x,int fa){    register int i;    ans=min(ans,t[k-dis[x]]+d[x]);    for (i=0;i<edge[x].size();++i)        if(!vis[edge[x][i].to]&&edge[x][i].to!=fa)        {            d[edge[x][i].to]=d[x]+1;            dis[edge[x][i].to]=dis[x]+edge[x][i].cost;            if(dis[edge[x][i].to]<=k)                cal(edge[x][i].to,x);        }    return ;}void work(int x){    register int i;    vis[x]=1,t[0]=0;    for (i=0;i<edge[x].size();++i)        if(!vis[edge[x][i].to])            dis[edge[x][i].to]=edge[x][i].cost,d[edge[x][i].to]=1,            dis[edge[x][i].to]<=k?cal(edge[x][i].to,0),add(edge[x][i].to,0,1),0:0;    for (i=0;i<edge[x].size();++i)        if(!vis[edge[x][i].to])            dis[edge[x][i].to]<=k?add(edge[x][i].to,0,0),0:0;    for (int i=0;i<edge[x].size();++i)        if(!vis[edge[x][i].to])            sum=size[edge[x][i].to],root=0,dfs1(edge[x][i].to,0),work(root);    return ;}int main(void){    register int i,x,y,z;    n=read(),k=read();    for (i=1;i<=k;++i)        t[i]=1e9;    for (i=1;i<n;++i)        x=read()+1,y=read()+1,z=read(),edge[x].push_back(Edge(y,z)),edge[y].push_back(Edge(x,z));    sum=n,mx[0]=1e9,dfs1(1,0),work(root);    return ans==1e9?puts("-1"):printf("%d",ans),0;}
原创粉丝点击