刷题总结——大工程(bzoj3611)

题目:

Description

国家有一个大工程,要给一个非常大的交通网络里建一些新的通道。

我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上。

在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径。

现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道。

现在对于每个计划,我们想知道:

1.这些新通道的代价和

2.这些新通道中代价最小的是多少

3.这些新通道中代价最大的是多少

Input

第一行 n 表示点数。

接下来 n-1 行,每行两个数 a,b 表示 a 和 b 之间有一条边。

点从 1 开始标号。 接下来一行 q 表示计划数。

对每个计划有 2 行,第一行 k 表示这个计划选中了几个点。

第二行用空格隔开的 k 个互不相同的数表示选了哪 k 个点。

Output

输出 q 行,每行三个数分别表示代价和,最小代价,最大代价。

Sample Input

10

2 1

3 2

4 1

5 2

6 4

7 5

8 6

9 7

10 9

5

2

5 4

2

10 4

2

5 2

2

6 1

2

6 1

Sample Output

3 3 3

6 6 6

1 1 1

2 2 2

2 2 2

HINT

n<=1000000

q<=50000并且保证所有k之和<=2*n

题解:

先构造虚树,为了维护答案anssum,ansmin,ansmax我们需要维护每个点i的sonsum[i],maxdis[i],mindis[i],cnt[i]分别表示该点所在子树的所有特殊点到这一点的距离总和,该点所在子树中的一个特殊点到该点距离的最大值以及最小值,和该点所在子树中的特殊点数量和···具体怎么更新三个答案和维护这四个值看代码吧

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=1e6+5;
inline int R()
{
  char c;int f=0;
  for(c=getchar();c<‘0‘||c>‘9‘;c=getchar());
  for(;c<=‘9‘&&c>=‘0‘;c=getchar())
    f=(f<<3)+(f<<1)+c-‘0‘;
  return f;
}
int fst[N],go[N*2],nxt[N*2],tot,dfn[N],deep[N],g[N][25],Cnt;
int vir[N],tag[N],tmp,stack[N],top,vn,tn,par[N];
int n,m,ansmax,ansmin,cnt[N],maxdis[N],mindis[N];
long long anssum,sonsum[N];
inline void comb(int a,int b)
{
  nxt[++tot]=fst[a],fst[a]=tot,go[tot]=b;
  nxt[++tot]=fst[b],fst[b]=tot,go[tot]=a;
}
inline void comb1(int a,int b)
{
  nxt[++tot]=fst[a],fst[a]=tot,go[tot]=b;
}
inline void dfs(int u,int fa)
{
  dfn[u]=++Cnt;
  for(int e=fst[u];e;e=nxt[e])
  {
    int v=go[e];
    if(v==fa)  continue;
    deep[v]=deep[u]+1;g[v][0]=u;
    dfs(v,u);
  }
}
inline int get(int a,int b)
{
  int i,j;
  if(deep[a]<deep[b])  swap(a,b);
  for(i=0;(1<<i)<=deep[a];i++);i--;
  for(j=i;j>=0;j--)
    if(deep[a]-(1<<j)>=deep[b])
      a=g[a][j];
  if(a==b)  return a;
  for(i=20;i>=0;i--)
    if(g[a][i]!=g[b][i])
      a=g[a][i],b=g[b][i];
  return g[a][0];
}
inline void pre()
{
  tot=stack[top=0]=0,tmp++,anssum=0,ansmin=1e+8,ansmax=0;
}
inline bool cmp(int a,int b)
{
  return dfn[a]<dfn[b];
}
inline void build()
{
  sort(vir+1,vir+vn+1,cmp);
  vn=unique(vir+1,vir+vn+1)-vir-1;tn=vn;
  for(int i=1;i<=tn;i++)
  {
    if(!top)
    {
      par[vir[i]]=0;stack[++top]=vir[i];fst[stack[top]]=0;
      continue;
    }
    int lca=get(vir[i],stack[top]);
    while(deep[stack[top]]>deep[lca])
    {
      if(deep[stack[top-1]]<deep[lca])  par[stack[top]]=lca;
      top--;
    }
    if(stack[top]!=lca)
    {
      par[lca]=stack[top];
      vir[++vn]=lca;
      stack[++top]=lca;fst[stack[top]]=0;
    }
    stack[++top]=vir[i];fst[stack[top]]=0;
    par[vir[i]]=lca;
  }
  sort(vir+1,vir+vn+1,cmp);
}
inline void dp(int u)
{
  cnt[u]=(tag[u]==tmp?1:0);sonsum[u]=0;
  maxdis[u]=0;mindis[u]=(tag[u]==tmp?0:1e+8);
  for(int e=fst[u];e;e=nxt[e])
  {
    int v=go[e];dp(v);
    ansmin=min(ansmin,mindis[u]+mindis[v]+deep[v]-deep[u]);
    ansmax=max(ansmax,maxdis[u]+maxdis[v]+deep[v]-deep[u]);
    anssum+=(long long)cnt[u]*cnt[v]*(deep[v]-deep[u])+(long long)sonsum[u]*cnt[v]+(long long)sonsum[v]*cnt[u];
    maxdis[u]=max(maxdis[u],maxdis[v]+deep[v]-deep[u]);
    mindis[u]=min(mindis[u],mindis[v]+deep[v]-deep[u]);
    sonsum[u]+=(sonsum[v]+(long long)cnt[v]*(deep[v]-deep[u]));
    cnt[u]+=cnt[v];
  }
}
int main()
{
  freopen("a.in","r",stdin);
  n=R();int a,b;
  for(int i=1;i<n;i++)
  {
    a=R(),b=R();
    comb(a,b);
  }
  deep[1]=1;
  dfs(1,0);
  for(int i=1;i<=20;i++)
    for(int j=1;j<=n;j++)
      g[j][i]=g[g[j][i-1]][i-1];
  m=R();
  while(m--)
  {
    vn=R();pre();
    for(int i=1;i<=vn;i++)  vir[i]=R(),tag[vir[i]]=tmp;
    build();
    for(int i=2;i<=vn;i++)  comb1(par[vir[i]],vir[i]);
    dp(vir[1]);
    printf("%lld %d %d\n",anssum,ansmin,ansmax);
  }
  return 0;
}
时间: 2024-12-27 21:39:22

刷题总结——大工程(bzoj3611)的相关文章

【BZOJ3611】大工程(虚树,动态规划)

[BZOJ3611]大工程(虚树,动态规划) 题面 BZOJ Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径. 现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道. 现在对于每个计划,我们想知道: 1.这些新通道的代价和 2.这些新通道中代价最小的是多

BZOJ3611 [Heoi2014]大工程 【虚树】

题目 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径. 现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道. 现在对于每个计划,我们想知道: 1.这些新通道的代价和 2.这些新通道中代价最小的是多少 3.这些新通道中代价最大的是多少 输入格式 第一行 n 表示点数. 接下来

[Bzoj3611][Heoi2014]大工程(虚树)

3611: [Heoi2014]大工程 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 2000  Solved: 837[Submit][Status][Discuss] Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径. 现在国家有很多个计划,每个计划都是这样,

雅虎刷题狂人曹鹏:10年理论与实践结合的程序员之路

曹鹏,2006年浙江大学计算机科学专业毕业,2013年中国科学院计算机技术研究所博士毕业.博士期间研究方向为社交网络与社会计算,曾经做过搜索.话题发现.社交网络方面.推荐算法等领域的相关研究. 曾为浙江大学.浙江省大学生程序设计竞赛的命题人,是hackerrank.com.hackerearth.com和csdn英雄会.CSDN高校编程挑战的命题人,也是PAT(Programming Ability Test, http://pat.zju.edu.cn/) 的命题人.是国内ZOJ(http:/

LeetCode的刷题利器(伪装到老板都无法diss你没有工作)

在工程效率大行其道的今天,如果不会写点代码以后也不容易在测试圈混下去.今天给大家推荐一个LeetCode的刷题利器,可以伪装到连你老板在这里走过去都无法确认你是在干活呢,还是在干活呢. LeetCode是什么 leetcode是个题库,里面有很编程多面试的题目,可以在线编译运行.难度比较高.如果自己能都做出来,对面大公司很有帮助. 网址:https://leetcode.com/(如果对英文页面不爽的可以访问对应的中文页面:https://leetcode-cn.com/) 如果想在上面训练,首

用js刷题的一些坑

leecode可以用js刷题了,我大js越来越被认可了是吧.但是刷题中会因为忽略js的一些特性掉入坑里.我这里总结一下我掉过的坑. 坑1:js中数组对象是引用对象 js中除了object还有数组对象也是引用对象,这点常常被忽视,所以在递归的时候传递数组要用arr.slice(0)这样复制一个一样的新数组,不然会出现你传入的数组会被同级的递归改变,结果就不对了. 所以只要数组复制的地方最好都要这么写,除非你真的想引用.而且注意是slice不是splice这两个方法差别很大,你如果用splice(0

停课刷题总结-给自己一点鼓励吧

嗯,我已经停了四五天课在家刷BZOJ准备复赛了,感觉压力好大.但是,实际上感觉效率并不高,每天就是7-8题的样子,而且并不是每题都有质量.而且这几天刷下来,我貌似因为刷了太多水题的关系,打字写题的速度变慢了,有一点悠闲没有紧迫感了,要赶快把这个习惯给改掉!今天去学校做题被虐了,竟然一个简单的Hash没有调对[虽然我现在还是不知道为什么会死循环QAQ.]感觉吧,可能因为刷题有点不在状态了.[其实也因为刷题的间隙玩了几盘LOL,游戏这东西QAQ]被虐了,感觉很不爽,有点难受,毕竟我付出了那么多努力,

BZOJ 刷题记录 PART 4

[BZOJ1143]CTSC的题目...先用floyed传递闭包,然后直接上匈牙利算法. [BZOJ1452]从未写过的二维树状数组.好像很简单.. struct two_bit { int f[305][305]; inline void add(int x,int z,int A) { for (;x<=n;x+=L(x)) for (int y=z;y<=m;y+=L(y)) f[x][y]+=A; } inline int ask(int x,int z) { int ans=0; f

COGS2642 / Bzoj4590 [Shoi2015]自动刷题机

Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 906  Solved: 321 Description 曾经发明了信号增幅仪的发明家SHTSC又公开了他的新发明:自动刷题机--一种可以自动AC题目的神秘装置.自动 刷题机刷题的方式非常简单:首先会瞬间得出题目的正确做法,然后开始写程序,每秒,自动刷题机的代码生成模 块会有两种可能的结果: A.写了x行代码. B.心情不好,删掉了之前写的y行代码.(如果y大于当前代码长度则相当于全部删除.) 对于每