Road
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1283 Accepted Submission(s): 361
Problem 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.)
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<=n,m<=200000), next line contains n-1 integers. The i-th integer
wi
(1<=
wi
<=1000) indicates the charge for the segment between village i and village i+1 being open for one day. Next m lines, each line contains two integers
ai,bi(1≤ai,bi<=n,ai!=bi)
.
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
Author
BUPT
Source
思路:只需要获得每段路的开始时间和关闭时间就ok了,但是数据比较大 O(n^2) 必然是不行的
我们把每一段路作为一个点,并赋予价值,然后我们离线处理给出的工作,首先我们从后往前,对给出的工作里的路段去更新它的开始时间,比如样例中,最后一天的工作为2 到 4,也就是第二段和第三段路,我们就可以将第二段和第三段路的开始时间更新为 3 (表示第三天开始),然后继续相前,就能得到最优的开始时间,然后拿动态数组Begin存下每个点的开始时间,然后同样的操作从前往后更新结束时间,存在End数组里。
处理完后,从第一天开始,在Begin数组里把第一天开启的路线的价值加到ans里,然后输出ans就是第一天的花费。
然后第一天结束,如果第一天有需要关闭的道路,那就减去它的价值,就这样一直处理到尾
ps:个人感觉其实不用线段树,直接拿两个数组出来也是可以在时间内统计出所有开始和结束时间的
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define maxn 200005
int w[maxn],l[maxn],r[maxn];
vector<int>Begin[maxn],End[maxn];
struct node{
int l,r,v;
}tree[maxn * 4];
int a[maxn];
void build(int i,int l,int r){
tree[i].l = l;
tree[i].r = r;
tree[i].v = -1;
if(l == r)
return ;
int mid = (l + r) >> 1;
build(i << 1,l,mid);
build(i << 1 | 1,mid + 1,r);
}
void update(int i,int l,int r,int val){ //这是单点更新
if(l <= tree[i].l && r >= tree[i].r){
tree[i].v = val;
return ;
}
if(tree[i].v != -1){ //直接更新到根节点就好
tree[i << 1].v = tree[i << 1 | 1].v = tree[i].v;
tree[i].v = -1;
}
int mid = (tree[i].l + tree[i].r) >> 1;
if(l <= mid)
update(i << 1,l,r,val);
if(r > mid)
update(i << 1 | 1,l,r,val);
}
int query(int i,int pos){
if(tree[i].l == tree[i].r)
return tree[i].v;
if(tree[i].v != -1){
return tree[i].v;
}
int mid = (tree[i].l + tree[i].r) >> 1;
if(pos <= mid)
return query(i << 1,pos);
else
return query(i << 1 | 1,pos);
}
int main(){
int n,m;
while(scanf("%d %d",&n,&m) != EOF){
for(int i = 1;i < n;i++){
scanf("%d",&w[i]); //输入每段路价值
}
for(int i = 1;i <= m;i++){
Begin[i].clear(); //情况动态数组
End[i].clear();
scanf("%d %d",&l[i],&r[i]);
if(l[i] > r[i]) //保证左比右小
swap(l[i],r[i]);
}
build(1,1,n - 1); // 清空线段树
for(int i = m;i >= 1;i--){
update(1,l[i],r[i] - 1,i); //从后往前更新每段路的开始日期
}
for(int i = 1;i < n;i++){
int day = query(1,i); //更新完之后查询每段路的开始时间做个记录
if(day != -1)
Begin[day].push_back(i);
}
build(1,1,n - 1); //清空
for(int i = 1;i <= m;i++) //从前往后更新每段路的结束日期
update(1,l[i],r[i] - 1,i);
for(int i = 1;i < n;i++){
int day = query(1,i); //记录
if(day != -1)
End[day].push_back(i);
}
int ans = 0;
for(int i = 1;i <= m;i++){ //一天天来
int len = Begin[i].size();
for(int j = 0;j < len;j++){
int x = Begin[i][j]; //在今天开始的路把价值加上
ans += w[x];
}
printf("%d\n",ans); //输入今天的价值
len = End[i].size();
for(int j = 0;j < len;j++){ //如果今天有关闭的路,那么减掉它们的价值
int x = End[i][j];
ans -= w[x];
}
}
}
return 0;
}