HDU 5861 Road (线段树)
Road
题目链接:
http://acm.split.hdu.edu.cn/showproblem.php?pid=5861
Description
There are n villages along a high way, and divided the high way into n-1 segments. Each segment would charge a certain amount of money for being open for one day, and you can open or close an arbitrary segment in an arbitrary day, but you can open or close the segment for just one time, because the workers would be angry if you told them to work multiple period.
We know the transport plan in the next m days, each day there is one cargo need to transport from village ai to village bi, and you need to guarantee that the segments between ai and bi are open in the i-th day. Your boss wants to minimize the total cost of the next m days, and you need to tell him the charge for each day.
(At the beginning, all the segments are closed.)
Input
Multiple test case. For each test case, begins with two integers n, m(1
Output
For each test case, output m lines, each line contains the charge for the i-th day.
Sample Input
4 3
1 2 3
1 3
3 4
2 4
Sample Output
3
5
5
Source
2016 Multi-University Training Contest 10
##题意:
水平线上n个村子间有 n-1 条路. 每条路开放一天的价格为 Cost_i.
有 m 天的操作,每天需要用到村子 Ai~Bi 间的道路.
每条路只能开放或关闭一次. (不能重复开关)
求每天的最小花费.
##题解:
用了两次线段树维护,写得很丑,还不如写两次线段树.
第一次线段树:
维护每条路第一次和最后一次被用到的天数.
以下代码维护了 mi:第一天,ma:最后一天,has:是否已经被用过.
mi和ma分别是子节点的最小值和最大值,关键是 has 的维护. (一开始没有写has, WA了)
has表示当前区间的结点是否都已经被用过.(即有mi值). 如果has=1那么就可以直接用lazy维护区间中所有结点的最大值.
若has=0意味着某个子节点还没有被用过, 若当前区间被lazy维护而没有更新到点,那么这个子节点的最小值就可能被改变.
这个地方关于维护的对象和lazy的处理做的不是很好,不过幸好过了. 晚点再改一下代码.
第二次线段树:
维护每天用了多少钱.
根据以上结果维护,对于每条路(被用到过的)区间更新第一次到最后一次这些天用的钱.
##代码:
``` cpp
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define eps 1e-8
#define maxn 201000
#define mod 100000007
#define inf 0x3f3f3f3f
#define mid(a,b) ((a+b)>>1)
#define IN freopen("in.txt","r",stdin);
using namespace std;
int n,m;
LL cost[maxn];
struct Tree
{
int left,right;
LL lazy,mi,ma,sum;
bool has;
}tree[maxn<<2];
bool flag;
void pushup(int i) {
tree[i].mi = min(tree[i<<1].mi, tree[i<<1|1].mi);
tree[i].ma = max(tree[i<<1].ma, tree[i<<1|1].ma);
tree[i].has = tree[i<<1].has && tree[i<<1|1].has;
if(flag) tree[i].sum = (tree[i<<1].sum + tree[i<<1|1].sum);
}
/递归建树/
void build(int i,int left,int right)
{
tree[i].left=left;
tree[i].right=right;
tree[i].lazy=0;
if(left==right){
tree[i].mi=inf;
tree[i].ma=-inf;
tree[i].has = 0;
tree[i].sum = 0;
return ;
}
int mid=mid(left,right);
build(i<<1,left,mid);
build(i<<1|1,mid+1,right);
pushup(i);
}
/区间修改,标记下传:每当访问到当前结点的子节点时,下传标记/
void pushdown(int i)
{
if(tree[i].lazy){
if(flag) {
tree[i<<1].lazy+=tree[i].lazy;
tree[i<<1|1].lazy+=tree[i].lazy;
tree[i<<1].sum+=(tree[i<<1].right-tree[i<<1].left+1)tree[i].lazy;
tree[i<<1|1].sum+=(tree[i<<1|1].right-tree[i<<1|1].left+1)tree[i].lazy;
tree[i].lazy=0; /下传后清零/
} else {
tree[i<<1].lazy=tree[i].lazy;
tree[i<<1|1].lazy=tree[i].lazy;
//tree[i<<1].mi = min(tree[i].lazy, tree[i<<1].mi);
//tree[i<<1|1].mi = min(tree[i].lazy, tree[i<<1|1].mi);
tree[i<<1].ma = max(tree[i].lazy, tree[i<<1].ma);
tree[i<<1|1].ma = max(tree[i].lazy, tree[i<<1|1].ma);
tree[i].lazy=0; /下传后清零/
}
}
}
/区间修改,d为改变量/
void update(int i,int left,int right,LL d)
{
if(tree[i].leftleft&&tree[i].rightright)
{
tree[i].mi = min(d, tree[i].mi);
tree[i].ma = max(d, tree[i].ma);
if(flag) {
tree[i].sum += (right-left+1) * d;
tree[i].lazy += d;
return;
} else {
if(tree[i].has) {
tree[i].lazy = d;
return;
}
if(tree[i].left==tree[i].right) {
if(!tree[i].has) tree[i].mi = tree[i].ma = d;
tree[i].has = 1;
return ;
}
}
}
pushdown(i);
int mid=mid(tree[i].left,tree[i].right);
if(right<=mid) update(i<<1,left,right,d);
else if(left>mid) update(i<<1|1,left,right,d);
else
{
update(i<<1,left,mid,d);
update(i<<1|1,mid+1,right,d);
}
pushup(i);
}
/区间结果查询/
typedef pair<LL,LL> pii;
pii query(int i,int left,int right)
{
if(tree[i].leftleft&&tree[i].rightright)
return make_pair(tree[i].mi,tree[i].ma);
pushdown(i);
int mid=mid(tree[i].left,tree[i].right);
if(right<=mid) return query(i<<1,left,right);
else if(left>mid) return query(i<<1|1,left,right);
//else return 0;
}
LL query_sum(int i,int left,int right)
{
if(tree[i].leftleft&&tree[i].rightright)
return tree[i].sum;
pushdown(i);
int mid=mid(tree[i].left,tree[i].right);
if(right<=mid) return query_sum(i<<1,left,right);
else if(left>mid) return query_sum(i<<1|1,left,right);
else return query_sum(i<<1,left,mid)+query_sum(i<<1|1,mid+1,right);
}
int starts[maxn], endss[maxn];
int main(int argc, char const *argv[])
{
//IN;
//int t; cin >> t;
while(scanf("%d %d", &n, &m) != EOF)
{
flag = 0;
for(int i=1; i<=n-1; i++)
scanf("%lld", &cost[i]);
build(1, 1, n-1);
for(int i=1; i<=m; i++) {
int x,y; scanf("%d %d", &x,&y);
if(x > y) swap(x, y);
update(1, x, y-1, i);
}
for(int i=1; i<=n-1; i++) {
pii tmp = query(1, i, i);
starts[i] = tmp.first;
endss[i] = tmp.second;
}
flag = 1;
build(1, 1, m);
for(int i=1; i<=n-1; i++) {
if(starts[i] == inf) continue;
update(1, starts[i], endss[i], cost[i]);
}
for(int i=1; i<=m; i++) {
printf("%lld\n", query_sum(1,i,i));
}
}
return 0;
}
HDU 5861 Road (线段树)的更多相关文章
- HDU 5861 Road 线段树区间更新单点查询
题目链接: http://acm.split.hdu.edu.cn/showproblem.php?pid=5861 Road Time Limit: 12000/6000 MS (Java/Othe ...
- hdu 5861 Road 两棵线段树
传送门:hdu 5861 Road 题意: 水平线上n个村子间有 n-1 条路. 每条路开放一天的价格为 Wi 有 m 天的操作,每天需要用到村子 Ai~Bi 间的道路 每条路只能开放或关闭一次. ( ...
- hdu 4031 attack 线段树区间更新
Attack Time Limit: 5000/3000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)Total Subm ...
- hdu 4288 离线线段树+间隔求和
Coder Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Su ...
- hdu 3016 dp+线段树
Man Down Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...
- 2016 Multi-University Training Contest 10 [HDU 5861] Road (线段树:区间覆盖+单点最大小)
HDU 5861 题意 在n个村庄之间存在n-1段路,令某段路开放一天需要交纳wi的费用,但是每段路只能开放一次,一旦关闭将不再开放.现在给你接下来m天内的计划,在第i天,需要对村庄ai到村庄bi的道 ...
- HDU 5861 Road(线段树 区间修改 单点查询)
Road Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submi ...
- HDU 5877 dfs+ 线段树(或+树状树组)
1.HDU 5877 Weak Pair 2.总结:有多种做法,这里写了dfs+线段树(或+树状树组),还可用主席树或平衡树,但还不会这两个 3.思路:利用dfs遍历子节点,同时对于每个子节点au, ...
- HDU 3308 LCIS (线段树区间合并)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目很好懂,就是单点更新,然后求区间的最长上升子序列. 线段树区间合并问题,注意合并的条件是a[ ...
随机推荐
- 转:ORACLE的JDBC连接方式:OCI和THIN
oracle的jdbc连接方式:oci和thin oci和thin是Oracle提供的两套Java访问Oracle数据库方式. thin是一种瘦客户端的连接方式,即采用这种连接方式不需要安装oracl ...
- 记一次高级java工程师职位的面试
阿里在业内做java方面的有关开发可谓是一流的.它给我的第一印象,就是办事效率很高. 周日简历发过去,周一电话就打过来了,接到电话后,面试官很客气,问现在方面吗,我说现在在上班,有点忙,然后和面试官约 ...
- 基于EasyUi的快速开发框架
先看图,下边这个简单的增.删.改.查,如果自己写代码实现,这两个页需要多少行代码? 如果再有类似的增.删.改.查,又需要多少行代码? 我最近搞的这个快速开发框架中,代码行数不超过100. 两页的代码如 ...
- 浅谈网络爬虫爬js动态加载网页(三)
上一篇讨论了web driver对动态网页的抓取与分析,可以很清楚的看出这是一种集中式处理方式,简单说,就是利用服务器,打开一个真正的brower,然后将需要解析的地址交给浏览器,浏览器去解析,然后将 ...
- postgresql大批量数据导入方法
一直没有好好关注这个功能,昨天看了一下,数据库插入有瓶颈,今天研究了一下: 主要有以下方案: 1.使用copy从文件导入: copy table_001(a, b, "f", d, ...
- 51nod 最长递增子序列
nlogn版最长递增子序列.线段树.(其实常数蛮大的....) #include<iostream> #include<cstring> #include<algorit ...
- (六)6.5 Neurons Networks Implements of Sparse Autoencoder
一大波matlab代码正在靠近.- -! sparse autoencoder的一个实例练习,这个例子所要实现的内容大概如下:从给定的很多张自然图片中截取出大小为8*8的小patches图片共1000 ...
- Spring AOP简介
AOP简述 AOP的概念早在上个世纪九十年代初就已经出现了,当时的研究人员通过对面向对象思想局限性的分析研究出了一种新的编程思想来帮助开发者减少代码重复提高开发效率,那就是AOP,Aspect-Ori ...
- 垂直的TextView
所先声明一下这个类是我从网上找到的一篇文章,只是保留并没有侵权的意思. public class TextViewVertical extends View { public static final ...
- WebView增加一个水平Progress,位置、长相随意
实际效果可以参看微信的web页面进度条 本质就是通过addView及对WebView 页面进度进行监听 先看看这个自定义的DrawableId,我们参照系统默认实现的方法写一个自己的 <la ...