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(2N1051Q105),表示总共的城市数以及订单数量。

第二行给出(N1)个数,顺次表示相邻两城市间的道路允许的最大运货重量Cii=0,,N2)。题目保证每个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 }

 

posted @ 2022-10-14 16:49  SAKURA12  阅读(99)  评论(0编辑  收藏  举报