标签:
这是为了真正去学一下点分治。。然后看了迪克李的ppt
又是一道写(改)了很久的题。。终于ac了
1354799 | orzliyicheng | 2599 | Accepted | 31936 kb | 23584 ms | C++/Edit | 2218 B | 2016-03-27 15:55:17 |
不算快呢。。具体实现是看的hzwer的blog,然而迪克李的ppt已经将想法讲得很清楚了
uoj文件里有,就懒得贴题解了
刚刚写完的时候,一个极限数据要跑60sec,我也是醉了。。主要原因有:
1.清空数组的时候竟然跑了n遍for循环,这不是显然O(n^2),我是不是傻。。(改完以后跑了30sec
2.getdeep,亦或是Add,都必须是对一整颗子树,我好像直接当前节点就开始了啊。。(这样下来时间就差不多了
然而还是有bug
都是一些没清零之类的问题。。晕@_@
然后就很开心地贴了,成功wa 要来数据发现第十个点就错了
改了有毛两个小时。。那是一条链的情况。。还以为有哪条路径没考虑到呢。。
原来只是边权为零的问题。。。。。。。。。
QAQ于是一个下午就这么过去了。。下次再写点分治应该效率会变高了吧
听说黄学长的getroot有一些问题会很慢。。?然而我并不觉得呀,还是留到以后再看吧。。(懒)
/************************************************************** Problem: 2599 User: orzliyicheng Language: C++ Result: Accepted Time:23584 ms Memory:31936 kb ****************************************************************/ #include<cstdio> #include<algorithm> #define N 400100 using namespace std; int edgenum,k,n,root,m,w,ans,sum,u,v,rn; int son[N],flag[N],vet[N],s[N],next[N],ff[N],f[1000100],head[N],pri[N],dis[1000100],fa[N]; void getroot(int u,int fa) { son[u]=1;ff[u]=0;int e=head[u]; while(e>0) { int v=vet[e]; if(flag[v]==0&&v!=fa) { getroot(v,u);son[u]+=son[v]; ff[u]=max(ff[u],son[v]); } e=next[e]; } ff[u]=max(ff[u],sum-son[u]); if(ff[u]<ff[root])root=u; } void Add(int u,int fa,int biao) { if(dis[u]<=k) { if(biao>0)f[dis[u]]=min(f[dis[u]],s[u]);else f[dis[u]]=n*2; } int e=head[u]; while(e>0) { int v=vet[e]; if(flag[v]==0)if(v!=fa) { Add(v,u,biao); } e=next[e]; } } void getdeep(int u,int fa) { if(k>=dis[u])if(f[k-dis[u]]+s[u]<ans)ans=f[k-dis[u]]+s[u]; int e=head[u]; while(e>0) { int v=vet[e]; if(flag[v]==0&&v!=fa) { s[v]=s[u]+1;dis[v]=dis[u]+pri[e]; getdeep(v,u); } e=next[e]; } } void work(int u) { dis[u]=0;s[u]=0;flag[u]=1; int e=head[u];rn=u; while(e>0) { int v=vet[e]; if(flag[v]==0) { dis[v]=dis[u]+pri[e];s[v]=s[u]+1; getdeep(v,0),Add(v,0,1); } e=next[e]; } e=head[u]; while(e>0) { int v=vet[e]; if(flag[v]==0)Add(v,0,0); e=next[e]; }f[0]=0; e=head[u]; while(e>0) { int v=vet[e]; if(flag[v]==0) { root=0;sum=son[v]; getroot(v,0);work(root); } e=next[e]; } } void add(int u,int v,int w) { edgenum++;vet[edgenum]=v;next[edgenum]=head[u];head[u]=edgenum; pri[edgenum]=w; } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n-1;i++) { scanf("%d%d%d",&u,&v,&w);u++;v++; add(u,v,w);add(v,u,w); } ff[0]=sum=n;ans=n*2; for(int i=1;i<=k;i++)f[i]=n*2; f[0]=0; root=0;getroot(1,0);work(root); if(ans>=n)ans=-1; printf("%d",ans); //fclose(stdin);fclose(stdout); }
算是吧省选一试以后的一个遗留问题给解决了。。
大家去安徽集训了,也不知道可以系统地做什么。。那就先颓一会儿文化课吧,先把月考给考了。嗯
标签:
原文地址:http://www.cnblogs.com/wxxlouisa/p/5325957.html