题解:P14598 [COCI 2025/2026 #2] 搭塔 / Tornjevi
这么典的莫队怎么能不写呢?
思路
首先因为第
发现一座塔肯定是形如 cpcpcp... 或者 pcpcpc... 的,于是考虑经典的括号序列匹配,将在同一座塔的点都染上相同的颜色。然后对询问就是区间数颜色了。
具体的,我们开两个栈维护未匹配的 P 和 C 的位置,然后遇到一个 P 我们就在 C 的栈里匹配,C 就在 P 的栈里匹配,将在同一个块的点都染上相同的颜色。
Code
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e05 + 700;
int n, m, tot;
int ans[MAXN], sum, cnt[MAXN];
char s[MAXN];
int a[MAXN], bel[MAXN];
stack <int> stp, stc;
struct qes {
int l, r, id;
} q[MAXN];
void init(int n)
{
int siz = sqrt(n), num = n / siz + 1;
for(int i = 1; i <= num; i++)
{
for(int j = (i - 1) * siz + 1; j <= i * siz; j++)
bel[j] = i;
}
return ;
}
bool cmp(qes a, qes b)
{
return (bel[a.l] ^ bel[b.l]) ? bel[a.l] < bel[b.l] : ((bel[a.l] & 1) ? a.r < b.r : a.r > b.r);
}
inline void add(int x)
{
if(!cnt[a[x]])
++sum;
cnt[a[x]]++;
return ;
}
inline void del(int x)
{
--cnt[a[x]];
if(!cnt[a[x]])
--sum;
return ;
}
signed main()
{
scanf("%d%d", &n, &m), scanf("%s", s + 1);
init(n);
for(int i = 1; i <= n; i++)
{
if(s[i] == 'P')
{
stp.push(i);
if(stc.size())
a[i] = a[stc.top()], stc.pop();
else
a[i] = ++tot;
}
else
{
stc.push(i);
if(stp.size())
a[i] = a[stp.top()], stp.pop();
else
a[i] = ++tot;
}
}
for(int i = 1; i <= m; i++)
scanf("%d%d", &q[i].l, &q[i].r), q[i].id = i;
sort(q + 1, q + m + 1, cmp);
int l = 1, r = 0;
for(int i = 1; i <= m; i++)
{
while(l < q[i].l)
del(l++);
while(l > q[i].l)
add(--l);
while(r < q[i].r)
add(++r);
while(r > q[i].r)
del(r--);
ans[q[i].id] = sum;
}
for(int i = 1; i <= m; i++)
printf("%d\n", ans[i]);
return 0;
}