【BZOJ3611】[Heoi2014]大工程

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 

题解:看到题时感觉不太难,到了对拍时发现网上题解都是虚树,然而蒟蒻没学过虚树啊,整个人都傻了。然而最后不用虚树还是做出来了~

首先由这样一个性质:两个点的LCA的深度,就是在欧拉序中,两个点间的所有点的深度的最小值。即:我们用ST表维护欧拉序中每个点的深度,求出两个位置中的深度最小值,就是两点LCA的深度。

那么,本题求的是所有点对的LCA的深度,那么我们不妨考虑每个LCA的深度对答案做的贡献。我们将k个点按照欧拉序排序,然后求出相邻两点之间的深度最小值,记为vj。我们考虑vj对答案做的贡献,即vj能成为那些点对的LCA的深度,即vj能成为那些区间中深度的最小值。显然可以用单调栈搞定。我们用单调栈求出每个vj左(右)边第一个比它大的v的位置,即为lp和rp。那么vj可以成为:一个点在[lp,j]中,一个点为[j+1,rp]中,所有这样的点对的LCA的深度。那么对于第一问,我们再维护一下深度的前缀和就搞定了。

那么第二问怎么办?根据贪心的思想,如果我们已经确定了vj,那么最优的点对一定满足:一个点是[lp,j]中深度最小的,一个点时[j+1,rp]中深度最小的。这就变成了RMQ问题,依旧上ST表。(本人坚信ST表的常数。)第三问同理。

细节:

1.为了防止重复,我们要稍微改变一下vj的定义。在排完序后的k个点中,设第j个点在欧拉序中的位置是pj,那么vj其实是[pj,pj+1)这段区间的深度最小值。你可能担心我们将最后一个点遗漏了,但是你会发现,欧拉序排在最后的点一定是不会成为任何点对的LCA的。所以不需要额外计算。
2.依旧为了防止重复,我们还要稍微改变一下lp,rp的定义。lp[j]:j左边,第一个<v[j]的位置;rp[j]:j右边,第一个>=v[j]的位置。特别地,如果不存在这样的位置,则令lp=0,rp=m。

其实这种做法跟虚树的思想差不多吧~

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=1000010;
typedef long long ll;
const int inf=1<<30;
ll sum;
int n,m,cnt,q,top,maxx,minn;
int dep[maxn],md[22][maxn<<1],p[maxn],to[maxn<<1],next[maxn<<1],head[maxn],Log[maxn<<1],pos[maxn];
int st[maxn],lp[maxn],rp[maxn],v[maxn],sn[22][maxn],sm[22][maxn];
ll s[maxn];
int rd()
{
int ret=0; char gc=getchar();
while(gc<'0'||gc>'9') gc=getchar();
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret;
}
void add(int a,int b)
{
to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
void dfs(int x)
{
pos[x]=++pos[0],md[0][pos[0]]=dep[x];
for(int i=head[x];i!=-1;i=next[i]) if(!dep[to[i]]) dep[to[i]]=dep[x]+1,dfs(to[i]),md[0][++pos[0]]=dep[x];
}
int getmin(int a,int b)
{
int k=Log[b-a+1];
return min(md[k][a],md[k][b-(1<<k)+1]);
}
int qm(int a,int b)
{
int k=Log[b-a+1];
return max(sm[k][a],sm[k][b-(1<<k)+1]);
}
int qn(int a,int b)
{
int k=Log[b-a+1];
return min(sn[k][a],sn[k][b-(1<<k)+1]);
}
bool cmp(int a,int b)
{
return pos[a]<pos[b];
}
int main()
{
n=rd();
int i,j,k,a,b;
memset(head,-1,sizeof(head));
memset(sm,0x80,sizeof(sm));
memset(sn,0x3f,sizeof(sn));
memset(md,0x3f,sizeof(md));
for(i=1;i<n;i++) a=rd(),b=rd(),add(a,b),add(b,a);
dep[1]=1,dfs(1);
for(i=2;i<=pos[0];i++) Log[i]=Log[i>>1]+1;
for(j=1;(1<<j)<=pos[0];j++) for(i=1;i+(1<<j)-1<=pos[0];i++) md[j][i]=min(md[j-1][i],md[j-1][i+(1<<j-1)]);
q=rd();
for(i=1;i<=q;i++)
{
m=rd(),sum=0,maxx=-inf,minn=inf;
for(j=1;j<=m;j++) p[j]=rd();
sort(p+1,p+m+1,cmp);
for(j=1;j<=m;j++) s[j]=s[j-1]+dep[p[j]],sm[0][j]=sn[0][j]=dep[p[j]];
for(k=1;(1<<k)<=m;k++) for(j=1;j+(1<<k)-1<=m;j++)
{
sm[k][j]=max(sm[k-1][j],sm[k-1][j+(1<<k-1)]);
sn[k][j]=min(sn[k-1][j],sn[k-1][j+(1<<k-1)]);
}
for(j=1;j<m;j++) v[j]=getmin(pos[p[j]],pos[p[j+1]]-1);
for(top=0,j=1;j<m;j++)
{
while(top&&v[st[top]]>v[j]) top--;
lp[j]=(top)?st[top]:0,st[++top]=j;
}
for(top=0,j=m-1;j;j--)
{
while(top&&v[st[top]]>=v[j]) top--;
rp[j]=(top)?st[top]:m,st[++top]=j;
}
for(j=1;j<m;j++)
{
sum-=(ll)(j-lp[j])*(rp[j]-j)*(2*v[j]);
sum+=(ll)(s[j]-s[lp[j]])*(rp[j]-j);
sum+=(ll)(s[rp[j]]-s[j])*(j-lp[j]);
maxx=max(maxx,qm(lp[j]+1,j)+qm(j+1,rp[j])-2*v[j]);
minn=min(minn,qn(lp[j]+1,j)+qn(j+1,rp[j])-2*v[j]);
}
for(j=1;j<=m;j++) sm[0][j]=-inf,sn[0][j]=inf;
printf("%lld %d %d\n",sum,minn,maxx);
}
return 0;
}

【BZOJ3611】[Heoi2014]大工程 欧拉序+ST表+单调栈的更多相关文章

  1. [BZOJ3611][Heoi2014]大工程

    [BZOJ3611][Heoi2014]大工程 试题描述 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道.  我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上.  在 ...

  2. [多校联考2019(Round 4 T2)][51nod 1288]汽油补给(ST表+单调栈)

    [51nod 1288]汽油补给(ST表+单调栈) 题面 有(N+1)个城市,0是起点N是终点,开车从0 -> 1 - > 2...... -> N,车每走1个单位距离消耗1个单位的 ...

  3. [BZOJ3611][Heoi2014]大工程(虚树上DP)

    3611: [Heoi2014]大工程 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 2464  Solved: 1104[Submit][Statu ...

  4. BZOJ2286 [Sdoi2011]消耗战 和 BZOJ3611 [Heoi2014]大工程

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6371  Solved: 2496[Submit][Statu ...

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

    3611: [Heoi2014]大工程 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 2000  Solved: 837[Submit][Status ...

  6. BZOJ3611 [Heoi2014]大工程 【虚树】

    题目 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a ...

  7. BZOJ3611:[HEOI2014]大工程(树形DP,虚树)

    Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道.  我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上.  在 2 个国家 a,b 之间建一条新通 ...

  8. BZOJ 4453: cys就是要拿英魂![后缀数组 ST表 单调栈类似物]

    4453: cys就是要拿英魂! Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 90  Solved: 46[Submit][Status][Discu ...

  9. 【题解】 bzoj3956: Count (ST表+单调栈)

    题面 Solution 看了一点点题解,自己又刚了\(2h30min\),刚了出来qwq,我好菜啊qwq 貌似这道题是BZOJ 4826的弱化,弱化都不会qwq凉凉 Solution 首先你可以考虑, ...

随机推荐

  1. Ticket Lock, CLH Lock, MCS Lock

    如果不用OS提供的mutex,我们该如何实现互斥锁?(不考虑重入的情况) 1. naive lock 最简单的想法是,搞一个volatile类型的共享变量flag,值可以是flase(无锁)或者tru ...

  2. Codeforces Gym100735 G.LCS Revised (KTU Programming Camp (Day 1) Lithuania, Birˇstonas, August 19, 2015)

    G.LCS Revised   The longest common subsequence is a well known DP problem: given two strings A and B ...

  3. (19)python scrapy框架

    安装scrapy pycharm 建个纯python工程 settings里 环境变量设置 C:\Python27;C:\Python27\Scripts; 下载win32api https://so ...

  4. POJ 3264 Balanced Lineup RMQ ST算法

    题意:有n头牛,编号从1到n,每头牛的身高已知.现有q次询问,每次询问给出a,b两个数.要求给出编号在a与b之间牛身高的最大值与最小值之差. 思路:标准的RMQ问题. RMQ问题是求给定区间内的最值问 ...

  5. java之properties和yml两种配置文件比较(非原创)

    文章大纲 一.内容介绍二.参考文章 一.内容介绍   我们在使用SpringBoot这个框架的时候都一定使用或者说是见到过application.properties或者是application.ym ...

  6. Tiny4412 支持 adb reboot-bootloader

    硬件版本:     Tiny4412ADK + S700 4GB u-boot 版本: u-boot-2010-12 linux版本:        Linux-3.0.8 版本一 支持 adb re ...

  7. VirtualBox 扩展虚拟硬盘容量

    转载:VirtualBox 扩展虚拟硬盘容量 如果使用的是ubuntu主机加xp虚拟机,扩容后,xp还无法识别扩大后的硬盘部分,可以在xp下使用“分区助手”进行处理,即将扩大的空间分给C盘.

  8. 键盘弹出后上提view隐藏后下拉view还原并修改scroll过程中旋转屏幕到竖屏view显示错误

    1,注册键盘相应事件 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillSho ...

  9. Android Touch事件传递机制详解 下

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38025165 资源下载:http://download.csdn.net/detail/yu ...

  10. Windows下批处理命令启动项目bat脚本

    文件env.cfg #server name SERVER_NAME=ActivitiService #JDK Home JDK_HOME= #Main MAIN_CLASS=com.nbtv.com ...