【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. [Python Cookbook] Numpy: Multiple Ways to Create an Array

    Convert from list Apply np.array() method to convert a list to a numpy array: import numpy as np myl ...

  2. java数据结构和算法10(堆)

    这篇我们说说堆这种数据结构,其实到这里就暂时把java的数据结构告一段落,感觉说的也差不多了,各种常见的数据结构都说到了,其实还有一种数据结构是“图”,然而暂时对图没啥兴趣,等有兴趣的再说:还有排序算 ...

  3. 全站之路一路坑(2)——在Apache下部署django博客

    上一篇博客:全栈之路一路坑之使用django开发博客 开发完博客之后,很多后续应用需要博客部署之后才可以使用,这篇文章就来尝试一下将开发好的博客部署到服务器上. 开发阶段,一直使用的是virtuale ...

  4. Http头 Range、Content-Range

    HTTP头中一般断点下载时才用到Range和Content-Range实体头,Range用户请求头中,指定第一个字节的位置和最后一个字节的位置,如(Range:200-300)Content-Rang ...

  5. python测试网络可达性的方法

    1.ping连通性测试 #!/usr/bin/env python #-*- coding: utf-8 -*- import os,sys,re import subprocess def NetC ...

  6. antialiasing

    Aliasing发生的原因在于,采样频率过低, 这样就无法重建更接近原来texture的图像, Temporal aliasing在时域上 采的texture 次数太少 不能重建真实 是帧与帧之间,s ...

  7. Libimseti推荐系统

    技术:easyUI.jQuery.Spring.Struts.Hibernate.Mahout.MySQL 本Libimseti推荐系统使用数据.代码參考<Mahout in action> ...

  8. jsp中jquery用法一步刷新 验证用户名是否存在

    <script type="text/javascript"> /* $(document).ready(function(){ var id="ha&quo ...

  9. hdu1394 Minimum Inversion Number(最小逆序数)

    Minimum Inversion Number Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/O ...

  10. 如何使用优化代码段替代WordPress插件

    每一个WordPress网站,都可以通过使用插件来获得更多的功能.但是太多的插件,会拖慢站点的运行速度,并且让站点看上去臃肿不堪. 一些插件的功能让你舍不得卸载,但是其实你可以使用简单的PHP代码来替 ...