BZOJ2286 [Sdoi2011]消耗战 和 BZOJ3611 [Heoi2014]大工程
2286: [Sdoi2011]消耗战
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 6371 Solved: 2496
[Submit][Status][Discuss]
Description
Input
第一行一个整数n,代表岛屿数量。
接下来n-1行,每行三个整数u,v,w,代表u号岛屿和v号岛屿由一条代价为c的桥梁直接相连,保证1<=u,v<=n且1<=c<=100000。
第n+1行,一个整数m,代表敌方机器能使用的次数。
接下来m行,每行一个整数ki,代表第i次后,有ki个岛屿资源丰富,接下来k个整数h1,h2,…hk,表示资源丰富岛屿的编号。
Output
输出有m行,分别代表每次任务的最小代价。
Sample Input
1 5 13
1 9 6
2 1 19
2 4 8
2 3 91
5 6 8
7 5 4
7 8 31
10 7 9
3
2 10 6
4 5 7 8 3
3 9 4 6
Sample Output
32
22
HINT
对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1
Source
[Submit][Status][Discuss]
HOME
Back
题解
虚树
虚树即是一颗虚拟构建的一棵树,这个树只包含关键点以及关键lca的点,而其他不影响虚树结构的点和边都相当于进行了路径压缩,整颗虚树的规模不会超过关键点数目的两倍.
对整颗树预处理得到dfs序(即前序遍历),记为dfn[u].
我们使用一个栈,从栈顶到栈底的元素形成虚树的一颗树链,我们就维护这一条链(有点类似笛卡尔树维护右链).
当我们得到一些询问点(关键点)的时候,对这些点按照他们的dfn[u]值进行排序,然后从dfn值小的开始扫描,结合栈中保存的树链信息就可以将这颗虚树构建出来.
假设我们当前扫到的关键点为u,栈指针为top,栈为stk.
- 如果栈为空,或者栈中只有一个元素,那么显然应该: stk[++top]=u;
- 取lca=LCA(u,stk[top]),如果lca=stk[top],则说明u点应该接着stk[top]点延长当前的树链.做操作: stk[++top]=u;
- 如果lca≠stk[top],则说明u与stk[top]分属lca的两颗不同的子树,且包含stk[top]的这颗子树应该已经构建完成了,我们需要做的是:
将lca的包含stk[top]子树的那部分退栈,并将这部分建边形成虚树.如果lca不在栈(树链)中,那么要把lca也加入栈中,保证虚树的结构不出现问题,随后将u加入栈中,以表延长树链
此题
对于这题建虚树然后简单DP一下就好了。然后这题特别处在于虚树不用建完,因为如果lca必选的话它的子树建出来就没有意义。所以第二种情况可以直接跳出。
时间复杂度\(O(n+\sum k\log n)\),因为使用了树剖求lca。
#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;rg char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std;
typedef pair<int,int> pii;
co int N=5e5+1;
int n,dep[N],fa[N],siz[N],son[N];
ll val[N];
int top[N],pos[N],dfn;
vector<pii> e[N];
void dfs1(int x,int fa){
dep[x]=dep[fa]+1,::fa[x]=fa,siz[x]=1;
for(int i=0,y;i<e[x].size();++i){
if((y=e[x][i].first)==fa) continue;
val[y]=min(val[x],(ll)e[x][i].second);
dfs1(y,x);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]]) son[x]=y;
}
}
void dfs2(int x,int top){
::top[x]=top,pos[x]=++dfn;
if(!son[x]) return;
dfs2(son[x],top);
for(int i=0,y;i<e[x].size();++i)
if(!::top[y=e[x][i].first]) dfs2(y,y);
}
int lca(int x,int y){
for(;top[x]!=top[y];x=fa[top[x]])
if(dep[top[x]]<dep[top[y]]) swap(x,y);
if(dep[x]>dep[y]) swap(x,y);
return x;
}
int a[N],s[N],t;
vector<int> ec[N];
il bool cmp(int a,int b){
return pos[a]<pos[b];
}
void insert(int x){
if(t==1) return s[++t]=x,void();
int lca=::lca(x,s[t]);
if(lca==s[t]) return; // notice
for(;t>1&&pos[s[t-1]]>=pos[lca];--t) ec[s[t-1]].push_back(s[t]);
if(lca!=s[t]) ec[lca].push_back(s[t]),s[t]=lca;
s[++t]=x;
}
ll dp(int x){
if(ec[x].size()==0) return val[x];
ll sum=0;
for(int i=0;i<ec[x].size();++i) sum+=dp(ec[x][i]);
ec[x].clear();
return min(sum,val[x]);
}
int main(){
read(n);
for(int i=1,u,v,w;i<n;++i){
read(u),read(v),read(w);
e[u].push_back(pii(v,w)),e[v].push_back(pii(u,w));
}
val[1]=1e18,dfs1(1,0),dfs2(1,1);
for(int m=read<int>(),k;m--;){
read(k);
for(int i=1;i<=k;++i) read(a[i]);
sort(a+1,a+k+1,cmp);
s[t=1]=1;
for(int i=1;i<=k;++i) insert(a[i]);
for(;t;--t) ec[s[t-1]].push_back(s[t]);
printf("%lld\n",dp(1));
}
return 0;
}
3611: [Heoi2014]大工程
Time Limit: 60 Sec Memory Limit: 512 MB
Submit: 2454 Solved: 1096
[Submit][Status][Discuss]
Description
Input
第一行 n 表示点数。
Output
输出 q 行,每行三个数分别表示代价和,最小代价,最大代价。
Sample Input
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
6 6 6
1 1 1
2 2 2
2 2 2
HINT
n<=1000000
Source
[Submit][Status][Discuss]
HOME
Back
题解
建立虚树。最大最小值DP非常显然。至于求和有两种办法:
- 统计每条边算了多少次
- 维护路径长度和sum和siz,每次ans+=sum[u]*siz[v]+siz[u]*(sum[v]+w*siz[v])。
注意只有实际询问的节点统计siz就行了。无聊啊……放一下别人的代码
第一种做法的
void dfs2(int x) {
siz[x]=bo[x],maxs[x]=0,mins[x]=inf,f[x]=0;
for (int y=now[x]; y; y=pre[y]) {
int d=dis[son[y]]-dis[x];
dfs2(son[y]),siz[x]+=siz[son[y]];
ans1=min(ans1,mins[x]+mins[son[y]]+d),mins[x]=min(mins[x],mins[son[y]]+d);
ans2=max(ans2,maxs[x]+maxs[son[y]]+d),maxs[x]=max(maxs[x],maxs[son[y]]+d);
f[x]+=f[son[y]]+1ll*siz[son[y]]*(num-siz[son[y]])*d;
}
if (bo[x]) ans1=min(ans1,mins[x]),ans2=max(ans2,maxs[x]),mins[x]=0;
now[x]=0;
}
第二种做法的
void dp(int u){
siz[u]=build[u];
mx[u]=build[u]?0:-inf;
mi[u]=build[u]?0:inf;
sum[u]=0;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
dp(v);
ans1+=(sum[u]+siz[u]*e[i].v)*siz[v]+sum[v]*siz[u];
siz[u]+=siz[v];
sum[u]+=sum[v]+siz[v]*e[i].v;
ans2=min(ans2,mi[u]+mi[v]+e[i].v);
ans3=max(ans3,mx[u]+mx[v]+e[i].v);
mi[u]=min(mi[u],mi[v]+e[i].v);
mx[u]=max(mx[u],mx[v]+e[i].v);
}
head[u]=0;
}
BZOJ2286 [Sdoi2011]消耗战 和 BZOJ3611 [Heoi2014]大工程的更多相关文章
- [BZOJ3611][Heoi2014]大工程
[BZOJ3611][Heoi2014]大工程 试题描述 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 ...
- [BZOJ3611][Heoi2014]大工程(虚树上DP)
3611: [Heoi2014]大工程 Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 2464 Solved: 1104[Submit][Statu ...
- [Bzoj3611][Heoi2014]大工程(虚树)
3611: [Heoi2014]大工程 Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 2000 Solved: 837[Submit][Status ...
- BZOJ3611:[HEOI2014]大工程(树形DP,虚树)
Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通 ...
- BZOJ3611 [Heoi2014]大工程 【虚树】
题目 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a ...
- BZOJ3611 HEOI2014大工程
先建虚树,然后统计答案. 对于这个两点间最大值和最小值的操作我参考了hzwer的代码. 建虚树时注意判自环 By:大奕哥 #include<bits/stdc++.h> using nam ...
- 虚树(Bzoj3611: [Heoi2014]大工程)
题面 传送门 虚树 把跟询问有关的点拿出来建树,为了方便树\(DP\) 在\(LCA\)处要合并答案,那么把这些点的\(LCA\)也拿出来 做法:把点按\(dfs\)序排列,然后求出相邻两个点的\(L ...
- [BZOJ3611] [Heoi2014]大工程(DP + 虚树)
传送门 $dp[i][0]$表示节点i到子树中的所有点的距离之和 $dp[i][1]$表示节点i到子树中最近距离的点的距离 $dp[i][2]$表示节点i到子树中最远距离的点的距离 建好虚树后dp即可 ...
- 【BZOJ3611】[Heoi2014]大工程 欧拉序+ST表+单调栈
[BZOJ3611][Heoi2014]大工程 Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶 ...
随机推荐
- 安装virtualBox 增强包
1 在原始操作系统安装. 2 打开USB设置. 3 运行虚拟机中的Linux中,Device->install guest additions 再安装增强包. 4 插入U盘,如果这时可以看到U盘 ...
- Django多对多的创建
1.多对多创建的应用场景: 在某表中创建一行数据是,有一个可以多选的下拉框 例如:创建用户信息,需要为用户指定多个爱好 2.创建方式: 方式一:自定义关系表,手动创建一张表用于关联其他多张表的关系 c ...
- GitHub提示 Error: Key already in use解决办法
GitHub提示 Error: Key already in use解决办法GitHub提示 Error: Key already in use解决办法2014年09月05日 ⁄ 综合 ⁄ 共 290 ...
- Python 面试题(上)
Python语言特性 1 Python的函数参数传递 看两个例子: a = 1 deffun(a): a = 2 fun(a) printa # 1 a = [] deffun(a): a.appen ...
- UVALive - 7045 Last Defence 【数学】
题目链接 https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_ ...
- PAT 天梯赛 L2-017. 人以群分 【排序】
题目链接 https://www.patest.cn/contests/gplt/L2-017 思路 第一个条件是 人群的规模尽可能接近 那么 N 为偶数的时候 就是 一半 一半 N 为奇数的时候 就 ...
- 转 开启“大数据”时代--大数据挑战与NoSQL数据库技术 iteye
一直觉得“大数据”这个名词离我很近,却又很遥远.最近不管是微博上,还是各种技术博客.论坛,碎碎念大数据概念的不胜枚举. 在我的理解里,从概念理解上来讲,大数据的目的在于更好的数据分析,否则如此大数据的 ...
- Linux平台下贪吃蛇游戏的运行
1.参考资料说明: 这是一个在Linux系统下实现的简单的贪吃蛇游戏,同学找帮忙,我就直接在Red Hat中调试了一下,参考的是百度文库中"maosuhan"仁兄的文章,结合自己的 ...
- 【二】MongoDB入门
下面是mongodb的一些基本概念: 文档是MongoDB中数据的基本单元,类似关系数据库中的行. 集合,是存储文档的容器,类似关系数据库中的表. MongoDB的单个实例容纳多个数据库,每个数据库都 ...
- String类型的对象,是保存在堆里还是在栈里呢?
在Java的实现中,new出来的String对象一般是放在堆中的. 如果是 String s ="xxx"; 这种,那就是放在常量池中. JDK6将常量池放在方法区中. 方法区此时 ...