[Codeforces]1389F – Bicolored Segments
本文最后更新于 153 天前,其中的信息可能已经有所发展或是发生改变。

Before the Beginning

转载请将本段放在文章开头显眼处,如有二次创作请标明。

原文链接:https://www.codein.icu/cf1389f/

题意

定义坏对为:两个线段相交且颜色不同。求最多选出多少个线段,能保证没有坏对。

解法

虽然两个颜色让人很容易想到二分图之类的东西,但这题更易理解的应该是动态规划做法。
先对坐标离散化一下方便处理。
定义 $f(i,j,k)$ 为 $[1,i]$ 的坐标区间中,保证 $[j + 1,i]$ 的颜色为 $k$ 能选出的最多线段。那么 $[1,j]$ 颜色与 $k$ 相反。
$f(i,j,k) = f(i-1,j,k) + \sum (L > j,R = i)$,即加入 $i$ 点后,贡献计入右端点为 $i$ 且颜色符合条件的线段。
首先 $i$ 可以滚动掉,而 $\sum (L > j,R = i)$,对于某一段连续的 $j$,值都是相同的,可以考虑用区间修改的数据结构维护。
这里选择使用线段树来维护。
对于 $R = i$ 的颜色为 $k$ 的线段,满足条件 $L > j$ 的区间为 $[1,L – 1]$,每次对区间 $[1,L – 1]$ 加 $1$ 即可转移。容易发现,每个线段只会进行一次区间修改操作,复杂度 $O(n\log n)$。
理论上要求 $j < i$,然而如果 $f(i,i-1,k)$ 从 $f(i-1,i-1,k)$ 来转移呢?因此需要给 $f(i,i,k)$ 也赋值,即颜色任意的情况,$f(i,i,k) = \max[f(i,j,k),f(i,j,!k)](j < i)$。
维护全局最大值即可用于更新 $f(i,i,k)$。
实现好像没啥细节。

#include <algorithm>
#include <cstdio>
#include <ctype.h>
#include <vector>
const int bufSize = 1e6;
using namespace std;
inline char nc()
{
#ifdef DEBUG
    return getchar();
#endif
    static char buf[bufSize], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, bufSize, stdin), p1 == p2) ? EOF : *p1++;
}
template <typename T>
inline T read(T& r)
{
    static char c;
    static int flag;
    flag = 1, r = 0;
    for (c = nc(); !isdigit(c); c = nc()) if (c == '-') flag = -1;
    for (; isdigit(c); c = nc()) r = r * 10 + c - 48;
    return r *= flag;
}
const int maxn = 4e5 + 100;
int n;
struct seg
{
    int l, r, t;
} S[maxn];
int H[maxn], cnt;
vector<pair<int, int> > V[maxn];
struct SegmentTree
{
    int maxx[maxn << 2], tag[maxn << 2];
    void pushdown(int p)
    {
        if (!tag[p]) return;
        maxx[p << 1] += tag[p], maxx[p << 1 | 1] += tag[p];
        tag[p << 1] += tag[p], tag[p << 1 | 1] += tag[p];
        tag[p] = 0;
    }
    void add(int l, int r, int p, int ll, int rr, int k)
    {
        if (ll > rr) return;
        if (l >= ll && r <= rr)
        {
            maxx[p] += k;
            tag[p] += k;
            return;
        }
        pushdown(p);
        int mid = l + r >> 1;
        if (ll <= mid) add(l, mid, p << 1, ll, rr, k);
        if (rr > mid) add(mid + 1, r, p << 1 | 1, ll, rr, k);
        maxx[p] = max(maxx[p << 1], maxx[p << 1 | 1]);
    }
    void modify(int l, int r, int p, int pos, int k)
    {
        if (l == r) return (void)(tag[p] = 0, maxx[p] = k);
        pushdown(p);
        int mid = l + r >> 1;
        if (pos <= mid) modify(l, mid, p << 1, pos, k);
        else modify(mid + 1, r, p << 1 | 1, pos, k);
        maxx[p] = max(maxx[p << 1], maxx[p << 1 | 1]);
    }
} T[2];
int main()
{
    read(n);
    H[++cnt] = 0;
    for (int i = 1; i <= n; ++i) read(S[i].l), read(S[i].r), read(S[i].t), H[++cnt] = S[i].l, H[++cnt] = S[i].r;
    sort(H + 1, H + 1 + cnt), cnt = unique(H + 1, H + 1 + cnt) - H - 1;
    for (int i = 1; i <= n; ++i)
    {
        S[i].l = lower_bound(H + 1, H + 1 + cnt, S[i].l) - H;
        S[i].r = lower_bound(H + 1, H + 1 + cnt, S[i].r) - H;
        V[S[i].r].push_back(make_pair(S[i].l, S[i].t - 1));
    }
    for (int i = 1; i <= cnt; ++i)
    {
        for (vector<pair<int, int> >::iterator it = V[i].begin(); it != V[i].end(); ++it)
        {
            int L = it->first, k = it->second;
            T[k].add(1, cnt, 1, 1, L - 1, 1);
        }
        int maxnum = max(T[0].maxx[1], T[1].maxx[1]);
        T[0].modify(1, cnt, 1, i, maxnum);
        T[1].modify(1, cnt, 1, i, maxnum);
    }
    printf("%d\n", max(T[0].maxx[1], T[1].maxx[1]));
    return 0;
}
本文标题:[Codeforces]1389F – Bicolored Segments
本文作者:Clouder
本文链接: https://www.codein.icu/cf1389f/
转载请标明。
暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇