【HDU5861】Road

题意

    有n个村庄排成一排,有n-1条路将他们连在一起。每条路开放一天都会花费一定数量的钱。你可以选择打开或者关上任意条路在任意一天,但是每条路只能打开和关闭一次。我们知道m天的运输计划。每天都有一辆马车从村庄ai到存在bi。你需要保证从ai到bi的路在第i天全部打开。如果要使花费最少,每天的花费应该是多少?n,m<=200000。

分析

   这个题应该有各种各样的做法吧。

   注意到,每条路只能打开和关上一次,我们可以很容易想到一个朴素的算法。

   记录下每条路最后一次用到的是哪一天。然后每一天如果需要的路是关闭的就打开它,如果这一天是某条路最后一次用,那么就关闭掉它。

   但是呢,暴力肯定是会超时的。我们发现,这n-1条路排成一排,而且每天的运输集合也是连续的一些路。我们把这些看作区间的话,就可以很容易的想到用线段树来维护。

   我这个题是用了两个线段树。

   第一棵线段树用来维护每一条路最后一次使用是哪一天。

   第二棵线段树用来维护当前开着的道路的花费总和。

   因为每条路只能打开和关闭一次,所以第二棵线段树的更新不需要打延时标记。

   每次查询的结果是当前的sumv[1]

   哇这样说好像说不明白哇。直接上代码好了··· 

   对了,我调了很久还是wa,最后发现,输入的时候要判断l,r的顺序,如果l>r的话需要swap(l,r)

  

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <iostream>
  5 #include <set>
  6 #include <vector>
  7 
  8 using namespace std;
  9 const int maxn=200000+10;
 10 vector<int>days[maxn];
 11 struct Node{
 12     int l,r;
 13 }a[maxn];
 14 int n,m;
 15 long long w[maxn];
 16 long long sumv[4*maxn],numv[4*maxn];
 17 int ql,qr;
 18 void update(int o,int L,int R){
 19     if(numv[o]==R-L+1)
 20         return;
 21     if(L==R){
 22         sumv[o]=w[L];
 23         numv[o]=1;
 24         return;
 25     }
 26     int M=L+(R-L)/2;
 27     if(ql<=M)
 28         update(2*o,L,M);
 29     if(qr>M)
 30         update(2*o+1,M+1,R);
 31     sumv[o]=sumv[2*o]+sumv[2*o+1];
 32     numv[o]=numv[2*o]+numv[2*o+1];
 33     return;
 34 }
 35 int v;
 36 void update2(int o,int L,int R){
 37     if(L==R){
 38         sumv[o]=0;
 39         numv[o]=0;
 40         return;
 41     }
 42     int M=L+(R-L)/2;
 43     if(v<=M)
 44          update2(2*o,L,M);
 45     else
 46          update2(2*o+1,M+1,R);
 47     sumv[o]=sumv[2*o]+sumv[2*o+1];
 48     numv[o]=numv[2*o]+numv[2*o+1];
 49     return;
 50 }
 51 int setv[4*maxn];
 52 void update3(int o,int L,int R){
 53     if(ql<=L&&qr>=R){
 54         setv[o]=v;
 55         return;
 56     }
 57     if(setv[o]){
 58       setv[2*o]=setv[o];
 59       setv[2*o+1]=setv[o];
 60       setv[o]=0;
 61     }
 62     int M=L+(R-L)/2;
 63     if(ql<=M)
 64         update3(2*o,L,M);
 65     if(qr>M)
 66         update3(2*o+1,M+1,R);
 67     return;
 68 }
 69 int query(int o,int L,int R){
 70     if(setv[o])return setv[o];
 71     if(L==R)
 72         return 0;
 73     int M=L+(R-L)/2;
 74     if(v<=M)
 75         return query(2*o,L,M);
 76     else
 77         return query(2*o+1,M+1,R);
 78 }
 79 int main(){
 80     while(scanf("%d%d",&n,&m)!=EOF){
 81         for(int i=1;i<=m;i++)days[i].clear();
 82         for(int i=1;i<n;i++)
 83             scanf("%lld",&w[i]);
 84         for(int i=1;i<=m;i++){
 85             scanf("%d%d",&a[i].l,&a[i].r);
 86             if(a[i].r<a[i].l)
 87                 swap(a[i].r,a[i].l);
 88 
 89             a[i].r--;
 90         }
 91         memset(setv,0,sizeof(setv));
 92         memset(sumv,0,sizeof(sumv));
 93         memset(numv,0,sizeof(numv));
 94         for(int i=1;i<=m;i++){
 95             ql=a[i].l,qr=a[i].r,v=i;
 96             update3(1,1,n-1);
 97         }
 98         for(int i=1;i<n;i++){
 99             v=i;
100             int res=query(1,1,n-1);
101             days[res].push_back(i);
102         }
103         for(int i=1;i<=m;i++){
104             ql=a[i].l,qr=a[i].r;
105             update(1,1,n-1);
106             printf("%lld
",sumv[1]);
107             for(int j=0;j<days[i].size();j++){
108                     v=days[i][j];
109                     update2(1,1,n-1);
110             }
111         }
112     }
113 return 0;
114 }
View Code
原文地址:https://www.cnblogs.com/LQLlulu/p/8965561.html