センセンはセンセンエクスプレスという宅配会社を設立しました。開業したばかりなので、ビジネスルートはとてもシンプルで、直線上にN都市とみなすことができ、左から右に0から(N-1)の番号が付けられています。道路の制限により、i番目の都市(i = 0、...、N-2)と(i + 1)の都市間で輸送される商品の重量は、同時にCikgを超えることはできません。
会社が設立された直後に、Qの注文を受けました。そのうち、jの注文には、S市からT市に輸送される特定の指定商品が記載されていました。ここでは、すべての商品に無制限のソースがあると単純に想定しており、Sensenは時々それらの一部を輸送用に選択します。安全上の理由から、これらの商品は途中で荷降ろしされません。
会社の全体的な効率を向上させるために、Sensenは、輸送される商品の重量が最大になり、道路の制限を満たすことができるように、注文の輸送をどのように手配するかを知りたいですか?納期はいつでも可能ですので、ご注文の際は、同じ道路を共有するすべてのトラックの総重量が過負荷にならないようにする必要があります。たとえば、都市1から都市4へ、および都市2から都市4への2つの注文の輸送を手配する場合、これら2つの注文の輸送は、2つの注文の2-3と3-4によって制限されます。商品はこれらの道路で同時に輸送される場合があります。
入力形式:
最初の行に2つの正の整数NとQ(2≤N≤105、1≤Q≤105)を入力し、都市の総数と注文数を示します。
2行目は、(N-1)の数を示しています。これは、2つの隣接する都市間の道路での最大許容貨物重量Ci(i = 0、...、N-2)を示しています。タイトルは、各Ciが231を超えない非負の整数であることを保証します。
次の行Qでは、各行に注文の開始出荷都市番号と終了出荷都市番号が示されています。タイトルは、すべての番号が合法であり、開始点と終了点の間に重複がないことを保証します。
出力形式:
輸送可能な商品の最大重量を1行で出力します。
入力例:
10 6
0 7 8 5 2 3 1 9 10
0 9
1 8
2 7
6 3
4 5
4 2
出力例:
7
プロンプトの例:最後の2つの注文を実行することを選択します。つまり、5kgの商品を受け取ります。都市4から都市2への輸送、および都市4から都市5への2キログラムの商品の輸送では、最大輸送量は7キログラムになります。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct node{
int u,v;
}a[100100];
int cmp(node x,node y)
{
if(x.v==y.v) return x.u>y.u;
return x.v<y.v;
}
struct {
int l,r,lazy;
ll v;
}tree[500100];
int num[100100];
void push_up(int root)
{
tree[root].v=min(tree[root*2].v,tree[root*2+1].v);
}
void build(int root,int l,int r)//建树,求出区间最小值,即可运输量
{
tree[root].l=l;tree[root].r=r;
tree[root].lazy=0;
if(l==r)
{
cin>>tree[root].v;
return;
}
int mid=(l+r)/2;
build(root*2,l,mid);
build(root*2+1,mid+1,r);
push_up(root);
}
void push_down(int root)//lazy标志更新
{
if(tree[root].lazy)
{
tree[root*2].lazy+=tree[root].lazy;
tree[root*2+1].lazy+=tree[root].lazy;
tree[root*2].v+=tree[root].lazy;
tree[root*2+1].v+=tree[root].lazy;
tree[root].lazy=0;
}
}
void update(int root,int l,int r,int val)//更新区间内每段可运输的最大重量
{
if(l<=tree[root].l&&r>=tree[root].r)
{
tree[root].lazy+=val;
tree[root].v+=val;
return;
}
if(tree[root].lazy) push_down(root);
int mid=(tree[root].l+tree[root].r)/2;
if(r<=mid) update(root*2,l,r,val);
else if(l>mid) update(root*2+1,l,r,val);
else
{
update(root*2,l,mid,val);
update(root*2+1,mid+1,r,val);
}
push_up(root);
}
ll query(int root,int l,int r)
{
if(l<=tree[root].l&&r>=tree[root].r)
return tree[root].v;
int mid=(tree[root].l+tree[root].r)/2;
if(tree[root].lazy) push_down(root);
ll ans;
if(r<=mid) return query(root*2,l,r);
else if(l>mid) return query(root*2+1,l,r);
else ans=min(query(root*2,l,mid),query(root*2+1,mid+1,r));
return ans;
}
int main()
{
ios::sync_with_stdio(false);
int n,q,u,v;
cin>>n>>q;
build(1,1,n-1);//建树
for(int i=1;i<=q;i++)
{
cin>>u>>v;
if(u>v) swap(u,v);
a[i].u=u;a[i].v=v;
}
sort(a+1,a+q+1,cmp);//排序,v小排前;v一样,u大排前
ll ans=0,num;
for(int i=1;i<=q;i++)
{
u=a[i].u;v=a[i].v;
num=query(1,u+1,v);
if(num>0) //如果可以取,更新
ans+=num,update(1,u+1,v,-num);
}
cout<<ans;
return 0;
}