码迷,mamicode.com
首页 > 其他好文 > 详细

[BZOJ2599][Race][IOI2011]点分治

时间:2016-03-27 17:38:07      阅读:163      评论:0      收藏:0      [点我收藏+]

标签:

这是为了真正去学一下点分治。。然后看了迪克李的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);
}

 算是吧省选一试以后的一个遗留问题给解决了。。

大家去安徽集训了,也不知道可以系统地做什么。。那就先颓一会儿文化课吧,先把月考给考了。嗯

[BZOJ2599][Race][IOI2011]点分治

标签:

原文地址:http://www.cnblogs.com/wxxlouisa/p/5325957.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!