1. 程式人生 > >題解:CF115E(線段樹優化dp)

題解:CF115E(線段樹優化dp)

定義 可能 bit tput space nbsp sans odi bsp

題目描述

你是一個賽車比賽的組織者,想在線性王國中安排一些比賽。

線性王國有n條連續的從左到右的道路。道路從左到右依次編號為從1到n,因此道路按照升序排列。在這些道路上可能會有幾場比賽,每一場比賽都將使用這些道路的某個連續的子序列。而且,如果某場比賽舉行了,你將獲得一定數額的金錢。沒有比賽在時間上重疊,所以每一段道路可以在多個比賽中使用。

不幸的是,所有道路的狀況都不佳,需要修理。每條路都有與之相關的維修費用,你需要支付這筆費用來修理道路。只有在某場比賽中需要使用的所有道路都進行了修復,才能進行比賽。你的任務是修復道路並使你的利潤最大化。你的利潤被定義為你從比賽中獲得的總金額減去你花在修理道路上的錢。請註意,您可以決定不修任何道路,並獲得利潤0。

輸出你能獲得的最大利潤。

輸入輸出格式

輸入格式:

第一行包括兩個整數n和m(1 \leq n,m \leq 2\cdot 10^5)(1n,m2?105),分別表示道路的數量和比賽的數量。

接下來n行,每行一個整數,表示這條道路修復需要的代價。

再接下來m行,每行包括三個整數l_b,u_b,p(1 \leq l_b,u_b \leq n,1 \leq p \leq 10^9)lb?,ub?,p(1lb?,ub?n,1p109),表示第b場比賽需要使用道路l_b,u_blb?,ub?,你會獲得收益p。

輸出格式:

輸出一個整數,表示你能獲得的最大利潤。

P.S.請不要使用%lld在C++中讀寫64位整數。推薦使用cin和cout流(也可以使用%I64d)。

說明

在第一個樣例中,最優解是修復1、2、3和7。你將會在第1、2、4三場比賽中獲得15的收益。道路修理費用是11,因此你的利潤是4

解題思路:

寫出dp方程,發現是區間求最大值,可以用線段樹維護

 1#include<bits/stdc++.h>
2#define N 200005
3#define int long long
4int c[N],dp[N];
5int now,n,m;
6struct node{
7 int l,r,val;
8}a[N];
9struct tre{
10 int lazy,mx;
11}tree[N*4];
12bool cmp
(node a, node b)
{
13 if (a.r==b.r)
14 return a.l<b.l; else
15 return a.r<b.r;
16}
17void read(){
18 std::cin >> n >> m;
19 for (int i=1;i<=n;i++)
20 std::cin >> c[i];
21 for (int i=1;i<=m;i++)
22 std::cin >> a[i].l >> a[i].r >> a[i].val;
23}
24void Add(int p,int l,int r,int v){
25 tree[p].lazy+=v;
26 tree[p].mx+=v;
27}
28void pushdown(int p,int l,int r,int mid){
29 if (tree[p].lazy==0) return;
30 Add(p<<1,l,mid,tree[p].lazy);
31 Add(p<<1|1,mid+1,r,tree[p].lazy);
32 tree[p].lazy=0;
33}
34void modify(int p,int l,int r,int x,int y,int v){
35 if (l>=x&&r<=y){
36 Add(p,l,r,v);
37 return;
38 }
39 int mid=l+r >> 1;
40 if (r<x||l>y) return;
41 pushdown(p,l,r,mid);
42 if (x<=mid) modify(p<<1,l,mid,x,y,v);
43 if (y>mid) modify(p<<1|1,mid+1,r,x,y,v);
44 tree[p].mx=std::max(tree[p<<1].mx,tree[p<<1|1].mx);
45}
46int query(int p,int l,int r,int x,int y){
47 if (l>=x&&r<=y){
48 return tree[p].mx;
49 }
50 int mid=l+r >> 1;
51 int res=0;
52 pushdown(p,l,r,mid);
53 if (x<=mid) res=std::max(res,query(p<<1,l,mid,x,y));
54 if (y>mid) res=std::max(res,query(p<<1|1,mid+1,r,x,y));
55 return res;
56}
57
58void solve(){
59 std::sort(a+1,a+m+1,cmp);
60 now=1;
61 for (int i=1;i<=n+1;i++){
62 while (now<=m&&a[now].r<i){
63 modify(1,0,n+1,0,a[now].l-1,a[now].val);
64 now++;
65 }
66 dp[i]=std::max(dp[i],query(1,0,n+1,0,i-1));
67 modify(1,0,n+1,i,i,dp[i]);
68 modify(1,0,n+1,0,i-1,-c[i]);
69 }
70 std::cout << dp[n+1] << std::endl;
71}
72main(){
73 read();
74 solve();
75 return 0;
76}

題解:CF115E(線段樹優化dp)