题目链接

(Gym) https://codeforces.com/gym/101480/standings
(BZOJ) 大人,时代变了。

题解

很神仙的题。
显然如果相邻两个数相等那么它们永远会相等,于是可以把相等的连续段缩到一起。
用链表维护所有的连续段,并对每个连续段维护以下信息:
\(l\),\(r\): 该连续段在原序列中对应的范围。
\(h\),\(t\): 该连续段上次更新的时间为 \(t\)、在那时的高度为 \(h\).
\(fa\),\(fb\): 发生 A/B 类操作时该连续段是否会增高。
那么在不发生合并操作的前提下,时刻 \(t_1\) 该连续段的高度为 \(h+fa(sa_{t_1}-sa_t)+fb(sb_{t_1}-sb_t)\),其中 \(sa_i,sb_i\) 分别表示前 \(i\) 个时刻 A 和 B 操作的个数。

对每一对相邻连续段,维护:
\(ga\),\(gb\): 发生 A/B 类操作时,两个连续段高度的差距是否会缩小(缩小的幅度只能是 \(0\)\(1\))。
并由此计算这两个连续段发生合并的时间,到时间的时候进行合并。
每次合并时,先计算新连续段的相关数值,然后检验新连通块相邻的两个连通块,计算合并时间,挂到对应的时间上。

时间复杂度 \(O(n+m)\).

代码

#include<bits/stdc++.h>
#define llong long long
#define mkpr make_pair
#define x first
#define y second
#define iter iterator
#define riter reverse_iterator
#define y1 Lorem_ipsum_
#define tm dolor_sit_amet_
#define pii pair<int,int>
using namespace std;

inline int read()
{
	int x = 0,f = 1; char ch = getchar();
	for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}
	for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}
	return x*f;
}

const int mxN = 3e5;
int n,q,tot,t;
int h[mxN+3];
char opt[mxN+3];
int sa[mxN+3],sb[mxN+3],ta[mxN+3],tb[mxN+3];
struct Node
{
	int prv,nxt,l,r,h,t,fa,fb,ga,gb; bool del;
} li[mxN*2+3];
queue<pii> que[mxN+3];

void calch(int u)
{
	if(!u) return;
	li[u].h += (sa[t]-sa[li[u].t])*li[u].fa+(sb[t]-sb[li[u].t])*li[u].fb;
	li[u].t = t;
}
void calcg(int u)
{
	if(li[u].del||li[li[u].prv].del) return;
	calch(u); calch(li[u].prv);
	if(li[u].h==li[li[u].prv].h) {que[t].push(mkpr(u,li[u].prv)); return;}
	li[u].ga = li[u].fa^li[li[u].prv].fa; li[u].gb = li[u].fb^li[li[u].prv].fb;
	int x = abs(li[u].h-li[li[u].prv].h);
	if(li[u].ga&&!li[u].gb) {if(sa[t]+x<=q) {que[ta[sa[t]+x]].push(mkpr(u,li[u].prv));}}
	else if(!li[u].ga&&li[u].gb) {if(sb[t]+x<=q) {que[tb[sb[t]+x]].push(mkpr(u,li[u].prv));}}
	else if(li[u].ga&&li[u].gb) {if(t+x<=q) {que[t+x].push(mkpr(u,li[u].prv));}}
}
void merge(int u,int v)
{
	if(li[u].del||li[v].del) return;
	tot++; li[tot].prv = li[li[u].prv].prv,li[tot].nxt = li[u].nxt,li[li[tot].prv].nxt = tot,li[li[tot].nxt].prv = tot; li[li[u].prv].del = li[u].del = true;
	calch(u); li[tot].h = li[u].h; li[tot].t = t; li[tot].l = li[li[u].prv].l,li[tot].r = li[u].r;
	calch(li[tot].prv); calch(li[tot].nxt); li[tot].fa = (li[li[tot].prv].h>li[tot].h); li[tot].fb = (li[li[tot].nxt].h>li[tot].h);
	if(li[tot].prv) {calcg(tot);} if(li[tot].nxt) {calcg(li[tot].nxt);}
}

int main()
{
	n = read(),q = read();
	for(int i=1; i<=n; i++) h[i] = read();
	scanf("%s",opt+1);
	for(int i=1; i<=q; i++) {sa[i] = sa[i-1],sb[i] = sb[i-1]; if(opt[i]=='A') {sa[i]++; ta[sa[i]] = i;} else {sb[i]++; tb[sb[i]] = i;}}
	for(int l=1; l<=n; l++)
	{
		int r = l; while(r<n&&h[r+1]==h[l]) {r++;}
		tot++; li[tot-1].nxt = tot,li[tot].prv = tot-1;
		li[tot].l = l,li[tot].r = r,li[tot].h = h[l],li[tot].t = 0; li[tot].fa = (h[l-1]>h[l]); li[tot].fb = (h[r+1]>h[r]);
		l = r;
	}
	for(int i=li[li[0].nxt].nxt; i; i=li[i].nxt) {calcg(i);}
	for(int i=1; i<=q; i++)
	{
		t = i;
		while(!que[i].empty())
		{
			pii u = que[i].front(); que[i].pop();
			merge(u.x,u.y);
		}
	}
	for(int i=li[0].nxt; i; i=li[i].nxt)
	{
		calch(i);
		for(int j=li[i].l; j<=li[i].r; j++) {printf("%d ",li[i].h);}
	}
	puts("");
	return 0;
}