2017年天梯赛全国总决赛题集 L3-2 森森快递
问题描述
森森开了一家快递公司,叫森森快递。因为公司刚刚开张,所以业务路线很简单,可以认为是一条直线上的N个城市,这些城市从左到右依次从0到(N−1)编号。由于道路限制,第i号城市(i=0,⋯,N−2)与第(i+1)号城市中间往返的运输货物重量在同一时刻不能超过Ci公斤。
公司开张后很快接到了Q张订单,其中j张订单描述了某些指定的货物要从Sj号城市运输到Tj号城市。这里我们简单地假设所有货物都有无限货源,森森会不定时地挑选其中一部分货物进行运输。安全起见,这些货物不会在中途卸货。
为了让公司整体效益更佳,森森想知道如何安排订单的运输,能使得运输的货物重量最大且符合道路的限制?要注意的是,发货时间有可能是任何时刻,所以我们安排订单的时候,必须保证共用同一条道路的所有货车的总重量不超载。例如我们安排1号城市到4号城市以及2号城市到4号城市两张订单的运输,则这两张订单的运输同时受2-3以及3-4两条道路的限制,因为两张订单的货物可能会同时在这些道路上运输。
输入格式
输入在第一行给出两个正整数N和Q(2≤N≤105, 1≤Q≤105),表示总共的城市数以及订单数量。
第二行给出(N−1)个数,顺次表示相邻两城市间的道路允许的最大运货重量Ci(i=0,⋯,N−2)。题目保证每个Ci是不超过231的非负整数。
接下来Q行,每行给出一张订单的起始及终止运输城市编号。题目保证所有编号合法,并且不存在起点和终点重合的情况。
输出格式
在一行中输出可运输货物的最大重量。
样例输入
10 6
0 7 8 5 2 3 1 9 10
0 9
1 8
2 7
6 3
4 5
4 2
样例输出
7
提示
我们选择执行最后两张订单,即把5公斤货从城市4运到城市2,并且把2公斤货从城市4运到城市5,就可以得到最大运输量7公斤。
题解
一张订单能运输的货物的最大值是区间[s,t]的最小值,
为了使运输货物的总量最大,要选尽量多的区间
考虑对区间右端点从小到大排序,越早结束的区间,留给其它区间的道路越多,所以优先选择结束早的区间
用线段树维护当前道路剩下的承重量,每选中一个区间就更新线段树,减掉该区间的重量
要注意输入的区间不一定左端点比右端点小,如果左端点大的话要交换,
还有,线段树保存的实际上是两个点之间的值,而我们读入的是端点,所以可以考虑线段树范围[0~n-2],读入时右端点-1;或者线段树[1~n-1],读入时左端点+1
无论是处理左端点还是处理右端点都要在交换后处理,交换前你以为你处理的是左端点其实处理的可能是右端点。。。我就是被这个卡了一下午。。。
1 #include <algorithm> 2 #include <cstdio> 3 #define ll long long 4 int n,Q,s,t; 5 ll w[100005],f[400005],tag[400005],c,ans; 6 struct node{ 7 int l,r; 8 }a[100005]; 9 ll mmin(ll x,ll y) 10 { 11 return x<y?x:y; 12 } 13 bool cmp(node x,node y) 14 { 15 return x.r<y.r; 16 } 17 void build(int l,int r,int id) 18 { 19 if (l==r) 20 { 21 f[id]=w[l]; 22 return; 23 } 24 int mid=(l+r)>>1,ls=id<<1,rs=ls|1; 25 build(l,mid,ls); 26 build(mid+1,r,rs); 27 f[id]=mmin(f[ls],f[rs]); 28 return; 29 } 30 void pushdown(int id) 31 { 32 if (!tag[id]) return; 33 int ls=id<<1,rs=ls|1; 34 tag[ls]+=tag[id]; 35 tag[rs]+=tag[id]; 36 f[ls]-=tag[id]; 37 f[rs]-=tag[id]; 38 tag[id]=0; 39 return; 40 } 41 void modify(int l,int r,int id) 42 { 43 if (s<=l && r<=t) 44 { 45 tag[id]+=c; 46 f[id]-=c; 47 return; 48 } 49 pushdown(id); 50 int mid=(l+r)>>1,ls=id<<1,rs=ls|1; 51 if (s<=mid) modify(l,mid,ls); 52 if (mid<t) modify(mid+1,r,rs); 53 f[id]=mmin(f[ls],f[rs]); 54 return; 55 } 56 ll query(int l,int r,int id) 57 { 58 if (s<=l && r<=t) return f[id]; 59 int mid=(l+r)>>1,ls=id<<1,rs=ls|1; 60 ll ans=1e18; 61 pushdown(id); 62 if (s<=mid) ans=mmin(ans,query(l,mid,ls)); 63 if (mid<t) ans=mmin(ans,query(mid+1,r,rs)); 64 f[id]=mmin(f[ls],f[rs]); 65 return ans; 66 } 67 int main() 68 { 69 int i,j; 70 scanf("%d%d",&n,&Q); 71 for (i=1;i<n;i++) 72 scanf("%lld",&w[i]); 73 n--; 74 build(1,n,1); 75 for (i=1;i<=Q;i++) 76 { 77 scanf("%d%d",&a[i].l,&a[i].r); 78 if (a[i].l>a[i].r) 79 a[i].l^=a[i].r, 80 a[i].r^=a[i].l, 81 a[i].l^=a[i].r; 82 a[i].l++; 83 } 84 std::sort(a+1,a+Q+1,cmp); 85 for (i=1;i<=Q;i++) 86 { 87 s=a[i].l; t=a[i].r; 88 c=query(1,n,1); 89 ans+=c; 90 modify(1,n,1); 91 } 92 printf("%lld",ans); 93 return 0; 94 }