[IOI2011] Race [点分治]
题面:
https://www.luogu.org/problemnew/show/P4149
bzoj恶心,这都放权限......
思路:
统计树上路径信息,点分治啊
K<=1e6,考虑对于距离为i的点建立tmp[i],表示在当前递归到的子树中,走到距离为i的顶点最少需要走多少边
点分治,每次先对每棵子树遍历,求出每个点i到root的距离dis[i],以及走过的边数d[i]
那么ans=min(ans,tmp[k-dis[i]]+d[i])
遍历完这棵子树再修改被访问了的tmp[dis[i]],然后下一棵
所有子树遍历完了以后,再遍历一遍所有节点,把修改到的tmp值变回inf(初始就是inf)
然后才对每一个子树找重心、递归下一步操作
注意:
tmp要开到1000000,不要开成n的大小
每次进入dfs_solve时tmp[0]=0,因为这个当前的根到自己距离为0,走过了0条边
注意常数优化
Code:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cstdlib> 6 #define inf 1e9 7 using namespace std; 8 inline int read(){ 9 int re=0,flag=1;char ch=getchar(); 10 while(ch>'9'||ch<'0'){ 11 if(ch=='-') flag=-1; 12 ch=getchar(); 13 } 14 while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar(); 15 return re*flag; 16 } 17 int n,m,cnt,sum,root,first[200010],siz[200010],son[200010]; 18 int d[200010],dis[200010],ans=inf,tmp[1000010]; 19 bool vis[200010]; 20 struct edge{ 21 int to,next,w; 22 }a[400010]; 23 inline void add(int u,int v,int w){ 24 a[++cnt]=(edge){v,first[u],w};first[u]=cnt; 25 a[++cnt]=(edge){u,first[v],w};first[v]=cnt; 26 } 27 inline int _max(int l,int r){return (l>r)?l:r;} 28 inline int _min(int l,int r){return (l<r)?l:r;} 29 void getroot(int u,int f){ 30 int i,v; 31 siz[u]=1;son[u]=0; 32 for(i=first[u];~i;i=a[i].next){ 33 v=a[i].to; 34 if(v==f||vis[v]) continue; 35 getroot(v,u); 36 siz[u]+=siz[v];son[u]=_max(son[u],siz[v]); 37 } 38 son[u]=_max(son[u],sum-siz[u]); 39 if(son[u]<son[root]) root=u; 40 } 41 void calc(int u,int f){ 42 int i,v; 43 if(dis[u]<=m) ans=_min(ans,tmp[m-dis[u]]+d[u]); 44 for(i=first[u];~i;i=a[i].next){ 45 v=a[i].to; 46 if(v==f||vis[v]) continue; 47 dis[v]=dis[u]+a[i].w;d[v]=d[u]+1; 48 calc(v,u); 49 } 50 } 51 void update(int u,int f,int t){ 52 int i,v; 53 if(dis[u]<=m){ 54 if(t) tmp[dis[u]]=_min(tmp[dis[u]],d[u]); 55 else tmp[dis[u]]=inf; 56 } 57 for(i=first[u];~i;i=a[i].next){ 58 v=a[i].to; 59 if(v==f||vis[v]) continue; 60 update(v,u,t); 61 } 62 } 63 void dfs(int u){ 64 int i,v;vis[u]=1;tmp[0]=0;//注意这里!!!!!!!!! 65 for(i=first[u];~i;i=a[i].next){ 66 v=a[i].to; 67 if(vis[v]) continue; 68 dis[v]=a[i].w;d[v]=1; 69 calc(v,0);update(v,0,1); 70 } 71 for(i=first[u];~i;i=a[i].next) if(!vis[a[i].to]) update(a[i].to,0,0); 72 for(i=first[u];~i;i=a[i].next){ 73 v=a[i].to; 74 if(vis[v]) continue; 75 sum=siz[v];root=0; 76 getroot(v,0); 77 dfs(root); 78 } 79 } 80 int main(){ 81 82 int size = 128 << 20; 83 char *p = (char*)malloc(size) + size; 84 __asm__("movl %0, %%esp\n" :: "r"(p));//有些OJ上不扩栈会RE 85 86 freopen("ioi2011-race.in","r",stdin); 87 freopen("ioi2011-race.out","w",stdout); 88 89 memset(first,-1,sizeof(first)); 90 int i,t1,t2,t3; 91 n=read();m=read(); 92 for(i=1;i<=m;i++) tmp[i]=inf; 93 for(i=1;i<n;i++){ 94 t1=read();t2=read();t3=read();//点是从零开始的 95 add(t1+1,t2+1,t3); 96 } 97 sum=n;root=0;son[0]=n; 98 getroot(1,0); 99 dfs(root); 100 if(ans!=inf) printf("%d\n",ans); 101 else printf("-1"); 102 }