D. Professor Higashikata

D. Professor Higashikata

Josuke is tired of his peaceful life in Morioh. Following in his nephew Jotaro's footsteps, he decides to study hard and become a professor of computer science. While looking up competitive programming problems online, he comes across the following one:

Let $s$ be a binary string of length $n$. An operation on $s$ is defined as choosing two distinct integers $i$ and $j$ ($1 \leq i < j \leq n$), and swapping the characters $s_i, s_j$.

Consider the $m$ strings $t_1, t_2, \ldots, t_m$, where $t_i$ is the substring $^\dagger$ of $s$ from $l_i$ to $r_i$. Define $t(s) = t_1+t_2+\ldots+t_m$ as the concatenation of the strings $t_i$ in that order.

There are $q$ updates to the string. In the $i$-th update $s_{x_i}$ gets flipped. That is if $s_{x_i}=1$, then $s_{x_i}$ becomes $0$ and vice versa. After each update, find the minimum number of operations one must perform on $s$ to make $t(s)$ lexicographically as large$^\ddagger$ as possible.

Note that no operation is actually performed. We are only interested in the number of operations.

Help Josuke in his dream by solving the problem for him.

——————————————————————

$\dagger$ A string $a$ is a substring of a string $b$ if $a$ can be obtained from $b$ by the deletion of several (possibly, zero or all) characters from the beginning and several (possibly, zero or all) characters from the end.

$\ddagger$ A string $a$ is lexicographically larger than a string $b$ of the same length if and only if the following holds:

  • in the first position where $a$ and $b$ differ, the string $a$ has a $1$, and the string $b$ has a $0$.

Input

The first line contains three integers $n$, $m$, $q$ ($1 \leq n,m,q \leq 2 \cdot 10^5$).

The next line contains a binary string $s$ of length $n$, consisting only of digits $0$ and $1$.

The $i$-th line of the next $m$ lines contains two integers $l_i$ and $r_i$ ($1 \leq l_i \leq r_i \leq n$).

The $i$-th line of the next $q$ lines contains a single integer $x_i$ ($1 \leq x_i \leq n$).

Output

Print $q$ integers. The $i$-th integer is the minimum number of operations that need to be performed on $s$ to get the lexicographically largest possible string $t(s)$ in the $i$-th round.

Examples

input

2 2 4
01
1 2
1 2
1
1
2
2

output

0
1
0
1

input

8 6 10
10011010
5 6
2 3
6 8
5 7
5 8
6 8
3
5
6
2
5
2
5
8
4
1

output

2
3
2
2
1
2
2
2
2
2

Note

In the first test case,

Originally, $t(s) = s(1,2) + s(1,2) = 0101$.

After the $1$-st query, $s$ becomes $11$ and consequently $t$ becomes $1111$. You don't need to perform any operation as $t(s)$ is already the lexicographically largest string possible.

After the $2$-nd query, $s$ becomes $01$ and consequently $t$ becomes $0101$. You need to perform $1$ operation by swapping $s_1$ and $s_2$. Consequently, $t(s)$ becomes $1010$ which is the lexicographically largest string you can achieve.

 

解题思路

  假设已经得到了 $T = t_1 + t2 + \cdots + t_m$,为了使得 $T$ 的字典序最大,我们应该让 $T$ 的某个前缀变成全 $1$,那么我们应该尽可能先让 $t_1$ 变为全 $1$,即通过交换使得 $s$ 中的 $i \in [l_1, r_1]$ 变成 $1$。然后再让 $t_2$ 变成全 $1$,以此类推。

  现在假设有 $t_i$ 和 $t_j$ 满足 $i < j$,且存在某个 $x$ 既满足 $x \in [l_i, r_i]$,且满足 $x \in [l_j, r_j]$。由于我们总是按下标从小到大对子串进行操作,因此如果在 $t_i$ 中将 $s_x$ 变成了 $1$,那么当要对 $t_j$ 进行操作,此时必然有 $s_x = 1$,无需再对 $s_x$ 进行交换。因此在 $T$ 中,我们只关心 $s$ 的每个下标第一次出现的位置,对于某个下标 $x$,当在 $T$ 中第一次出现并被交换成 $1$ 后,那么之后再次出现也不会再进行交换。

  我们只需按照原来的顺序保留 $T$ 中所有第一次出现的下标来得到 $t$,必然有 $|t| \leq n$。以第二个样例为例子:$$t = s_5s_6 \; s_2s_3 \; \bcancel{s_6}s_7s_8 \; \bcancel{s_5}\bcancel{s_6}\bcancel{s_7} \; \bcancel{s_5}\bcancel{s_6}\bcancel{s_7}\bcancel{s_8} \; \bcancel{s_6}\bcancel{s_7}\bcancel{s_8} = s_5s_6s_2s_3s_7s_8$$

  获得 $t$ 最暴力的做法是遍历每一个 $t_i$ 的 $[l_i, r_i]$,如果某个下标之前没被选过,那么就记录下来。很明显这样做的时间复杂度是 $O(m \cdot n)$,因为重复枚举了被选过的下标,因此可以开个 $\text{std::set}$ 或用并查集来维护还没有被选的下标,以此快速找到下一个还没被选的下标。这样时间复杂度就优化到 $O(m + n\log{n})$ 或 $O(m + n)$。

  在执行更新操作前先计算当前 $T$ 的答案,也就是 $t$ 的答案(最小的操作次数使得 $T$ 的字典序最大)。假设原始的 $s$ 中所有 $1$ 的个数为 $\text{sum}$,$t$ 的前 $i$ 个字符中 $1$ 的个数为 $c_i$ 分情况讨论:

  1. $\text{sum} \leq |t|$,那么我们就将 $t$ 的前 $\text{sum}$ 个字符所对应的 $s$ 的下标,在 $s$ 中全部交换成 $1$,那么最小的交换次数就是 $\text{sum} - c_{\text{sum}}$。
  2. $\text{sum} > |t|$,那么我们将 $t$ 中所有字符所对应的 $s$ 的下标全部交换成 $1$,最小交换次数就是 $|t| - c_{|t|}$。

  综合一下,答案就是 $\min \{ \text{sum}, |t| \} - c_{\min \{ \text{sum}, |t| \}}$。

  于是对于更新操作,我们只需维护 $\text{sum}$,以及 $t$ 的前缀中 $1$ 的个数,这里可以用树状数组来实现。

  $\text{std::set}$ 写法的 AC 代码如下,时间复杂度为 $O(m + n\log{n} + q\log{n})$:

#include <bits/stdc++.h>
using namespace std;
 
typedef long long LL;
 
const int N = 2e5 + 10;
 
char str[N];
vector<int> p;
int mp[N];
int tr[N];
 
int lowbit(int x) {
    return x & -x;
}
 
void add(int x, int c) {
    for (int i = x; i <= p.size(); i += lowbit(i)) {
        tr[i] += c;
    }
}
 
int query(int x) {
    int ret = 0;
    for (int i = x; i; i -= lowbit(i)) {
        ret += tr[i];
    }
    return ret;
}
 
int main() {
    int n, m, k;
    scanf("%d %d %d %s", &n, &m, &k, str + 1);
    set<int> st;
    for (int i = 1; i <= n; i++) {
        st.insert(i);
    }
    while (m--) {
        int l, r;
        scanf("%d %d", &l, &r);
        auto t = st.lower_bound(l);
        while (t != st.end() && *t <= r) {
            p.push_back(*t);
            t = st.erase(t);
        }
    }
    for (int i = 1; i <= p.size(); i++) {
        int x = p[i - 1];
        if (str[x] & 1) add(i, 1);
        mp[x] = i;
    }
    int s = count(str + 1, str + n + 1, '1');
    while (k--) {
        int x;
        scanf("%d", &x);
        if (str[x] & 1) {
            s--;
            if (mp[x]) add(mp[x], -1);
        }
        else {
            s++;
            if (mp[x]) add(mp[x], 1);
        }
        str[x] ^= 1;
        int t = min<int>(s, p.size());
        printf("%d\n", t - query(t));
    }
    
    return 0;
}

  并查集写法的 AC 代码如下,时间复杂度为 $O(m + n + q\log{n})$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 2e5 + 10;

char str[N];
int fa[N];
vector<int> p;
int mp[N];
int tr[N];

int find(int x) {
    return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
}

int lowbit(int x) {
    return x & -x;
}

void add(int x, int c) {
    for (int i = x; i <= p.size(); i += lowbit(i)) {
        tr[i] += c;
    }
}

int query(int x) {
    int ret = 0;
    for (int i = x; i; i -= lowbit(i)) {
        ret += tr[i];
    }
    return ret;
}

int main() {
    int n, m, k;
    scanf("%d %d %d %s", &n, &m, &k, str + 1);
    for (int i = 1; i <= n + 1; i++) {
        fa[i] = i;
    }
    while (m--) {
        int l, r;
        scanf("%d %d", &l, &r);
        for (int i = find(l); i <= r; i = fa[i]) {
            p.push_back(i);
            fa[i] = find(i + 1);
        }
    }
    for (int i = 1; i <= p.size(); i++) {
        int x = p[i - 1];
        if (str[x] & 1) add(i, 1);
        mp[x] = i;
    }
    int s = count(str + 1, str + n + 1, '1');
    while (k--) {
        int x;
        scanf("%d", &x);
        if (str[x] & 1) {
            s--;
            if (mp[x]) add(mp[x], -1);
        }
        else {
            s++;
            if (mp[x]) add(mp[x], 1);
        }
        str[x] ^= 1;
        int t = min<int>(s, p.size());
        printf("%d\n", t - query(t));
    }
    
    return 0;
}

 

参考资料

  Codeforces Round 882 Editorial:https://codeforces.com/blog/entry/117928

  Codeforces Round 882 (Div. 2)(A-D,待更新):https://zhuanlan.zhihu.com/p/642093526

posted @ 2023-10-18 14:55  onlyblues  阅读(5)  评论(0编辑  收藏  举报
Web Analytics