【題解】種樹

題目大意

  有\(n\)個格子(\(1 \leq n \leq 30000\)),每一個格子能夠種\(1\)棵樹。如今給你\(h\)個要求(\(1 \leq h \leq 5000\)),格式爲\(\boxed{l_i \text{ } r_i \text{ } t_i}\),表示要求格子區間\([l_i, r_i]\)中至少種\(t_i\)棵樹(\(1 \leq l_i \leq r_i \leq n\)\(0 \leq t_i \leq r_i - l_i + 1\))。問你最少要種多少棵樹才能知足全部要求。ios

題解

  很顯然的貪心策略,每次儘量靠近\(r_i\)種樹。
  咱們能夠用樹狀數組來查詢一段區間內有多少棵樹,而且修改每一個格子(對應種樹)。
  若是樸素枚舉哪些格子沒種樹,雖然能ac,但顯然不夠優。咱們能夠用並查集來維護對於每一個點\(i\),從\(i\)開始往\(1\)找,第\(1\)個沒有種樹的格子的位置\(p[i]\)
  初始化顯然爲\(p[i] = i\),而後對於每一個操做\(i\),咱們從\(r_i\)開始枚舉沒有種樹的格子\(j\),顯然剛開始是讓\(j = p[r_i]\)
  咱們如何肯定下一個沒有種樹的格子呢?其實咱們能夠直接使\(p[j] = p[j - 1]\),而後使\(j = p[j]\)便可,顯然這是可行的。數組

#include <iostream>
#include <cstdio>
#include <algorithm>

#define MAX_N (30000 + 5)
#define MAX_H (5000 + 5)

#define lowbit(x) ((x) & -(x))

using namespace std;

struct Node
{
    int l, r, t;
};

inline bool cmp(Node a, Node b)
{
    if (a.r != b.r) return a.r < b.r;
    return a.l < b.l;
};

int n, h;
Node a[MAX_H];
int s[MAX_N];
int p[MAX_N];

int GetRoot(int x)
{
    if (x == p[x]) return x;
    return p[x] = GetRoot(p[x]);
}

void Modify(int x)
{
    while (x <= n) ++s[x], x += lowbit(x);
    return;
}

int Query(int l, int r)
{
    --l;
    int sum = 0;
    while (r) sum += s[r], r -= lowbit(r);
    while (l) sum -= s[l], l -= lowbit(l);
    return sum;
}

int main()
{
    scanf("%d%d", &n, &h);
    for (int i = 1; i <= n; ++i)
    {
        p[i] = i;
    }
    for (int i = 1; i <= h; ++i)
    {
        scanf("%d%d%d", &a[i].l, &a[i].r, &a[i].t);
    }
    sort(a + 1, a + h + 1, cmp);
    int cnt;
    for (int i = 1; i <= h; ++i)
    {
        cnt = Query(a[i].l, a[i].r);
        for (int j = GetRoot(a[i].r); cnt < a[i].t; j = GetRoot(j))
        {
            Modify(j);
            ++cnt;
            p[j] = GetRoot(j - 1);
        }
    }
    printf("%d", Query(1, n));
    return 0;
}
相關文章
相關標籤/搜索