#C. gsy's watering plan (line segment tree+dp)

topic


train of thought

The knowledge point of the test is the line segment tree + dp .

We can follow the dp 4-step method to deduce step by step,

1.dp definition

dp[i] represents the minimum cost for the [1,i] interval to be covered by a given line segment

2. State transition equation

According to the definition of dp, it can be enumerated to the xth line , the interval is [Lx, Rx] , and the cost is Vx

dp[Rx]=min(dp[i](i = (Lx - 1) ~ Rx))+Vx

Because when you want to cover the interval of [1, Rx], you must add the xth line segment on the basis of covering [1, Lx - 1]/[1, Lx].../[1, Rx] .

And the minimum cost of covering [1,Lx - 1]/[1,Lx].../[1,Rx] is (dp[i](i = (Lx - 1) ~ Rx) , plus the xth item The cost of a line segment is Vx .

Draw a picture to understand:

这个时候会有个问题:在这里我们要求min(dp[i](i = (Lx - 1) ~ Rx),可是如果暴力枚举找min的话时间复杂度O(n*m)会超时,那该怎么办呢?我们可以用线段树(详见详解线段树)来实现查找区间最小值单点更新(dp在变)的效果。

3.初始化

一个是dp一开始要是无穷大,一个是minv(线段树的那个)也要初始化为无穷大,另外储存线段的数组也要以r从大到小排序(这样才能保证后续枚举线段时dp[i](i = (Lx - 1) ~ Rx是最优的)

4.遍历顺序

显然就是以下标顺序枚举所有线段。


代码

#include <bits/stdc++.h>
#define int long long
#define maxn 300000
using namespace std;
int n,m,dp[5000000],minv[5000000];
struct shui
{
  int l,r,v;
} a[5000000];
bool cmp(shui x,shui y)
{
  return x.r < y.r;
}
int find(int id,int l,int r,int x,int y)//查找[x,y]区间内的最小值
{
  if(x <= l && r <= y) return minv[id];
  int mid = (l + r) / 2,ans = INT_MAX;
  if(x <= mid) ans = min(ans,find(id * 2,l,mid,x,y));
  if(y > mid) ans = min(ans,find(id * 2 + 1,mid + 1,r,x,y));
  return ans;
}
void gexi(int id,int l,int r,int x,int v)//将编号为x的节点的值更改为v
{
  if(l == r)
  {
    minv[id] = v;
    return ;
  }
  int mid = (l + r) / 2;
  if(x <= mid) gexi(id * 2,l,mid,x,v);
  else gexi(id * 2 + 1,mid + 1,r,x,v);
  minv[id] = min(minv[id * 2],minv[id * 2 + 1]);
}
signed main()
{
  scanf("%lld%lld",&n,&m);
  for(int i = 1; i <= n; i++) scanf("%lld%lld%lld",&a[i].l,&a[i].r,&a[i].v);
  memset(dp,0x3f,sizeof(dp));
  memset(minv,0x3f,sizeof(minv));//minv对应的是dp
  sort(a + 1,a + 1 + n,cmp);
  for(int i = 1; i <= n; i++)
  {
    if(a[i].l == 1)
    {
      if(dp[a[i].r] > a[i].v)
      {
        dp[a[i].r] = a[i].v;
        gexi(1,1,maxn,a[i].r,a[i].v);
      }
    }
    else
    {
      int t = find(1,1,maxn,a[i].l - 1,a[i].r);
      if(dp[a[i].r] > (t + a[i].v))
      {
        dp[a[i].r] = t + a[i].v;
        gexi(1,1,maxn,a[i].r,dp[a[i].r]);
      }
    }
  }
  printf("%lld",dp[m]);
  return 0;
}

Guess you like

Origin blog.csdn.net/weq2011/article/details/128894345