[ABC285F] Substring of Sorted String

考虑什么样的区间可能满足要求。

满足要求的区间即一个是 SS 按照升序排序后的子串,那么显然这个子串也升序排序。

所以我们可以发现第一个要求是:区间 Sl,Sl+1,,SrS_l, S_{l+1}, \cdots, S_r 升序排序。

但是区间就算升序排序,也不一定满足要求。比如 SSabdpc\texttt{abdpc}。询问区间 [1,4][1,4],虽然 [1,4][1,4] 是递增的,但是排序后 c\texttt{c} 会排在 b,d\texttt{b,d} 之间,不满足要求。

于是可以发现,当区间升序排序,设 x=Sl+1x=S_l+1y=Sr1y = S_r - 1。那么 SS 中所有属于区间 [x,y][x,y] 的数的个数应该和第 llrr 中属于区间 [x,y][x,y] 的数相同。这样排序后这些数一定在一起。

线段树维护即可。

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

const int N = 2e5 + 5, INF = 2e9, MOD = 1e9 + 7;

inline int read()
{
	int op = 1, x = 0;
	char ch = getchar();
	while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
	while (ch == '-')
	{
		op = -op;
		ch = getchar();
	}
	while (ch >= '0' and ch <= '9')
	{
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x * op;
}

inline void write(int x)
{
	if (x < 0) putchar('-'), x = -x;
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}

int n, q;
string s;
int a[N];
bool a1[N], a2[N];

class SegmentTree
{
public:
	struct Node
	{
		int l, r, ll, rr;
		bool is_as;
		friend Node operator+(const Node& x, const Node& y)
		{
			Node c;
			c.ll = x.ll;
			c.rr = y.rr;
			c.is_as = x.is_as && y.is_as && (x.rr <= y.ll);
			return c;
		}
	}tr[N << 2];
	void pushup(int u)
	{
		tr[u].ll = tr[u << 1].ll;
		tr[u].rr = tr[u << 1 | 1].rr;
		tr[u].is_as = tr[u << 1].is_as && tr[u << 1 | 1].is_as && (tr[u << 1].rr <= tr[u << 1 | 1].ll);
	}
	void build(int u, int l, int r)
	{
		tr[u] = { l, r, a[l], a[l], 1 };
		if (l == r) return;
		int mid = l + r >> 1;
		build(u << 1, l, mid);
		build(u << 1 | 1, mid + 1, r);
		pushup(u);
	}
	void update(int u, int x, int v)
	{
		if (tr[u].l == tr[u].r)
		{
			tr[u].ll = tr[u].rr = v;
			return;
		}
		int mid = tr[u].l + tr[u].r >> 1;
		if (x <= mid) update(u << 1, x, v);
		else update(u << 1 | 1, x, v);
		pushup(u);
	}
	Node query(int u, int l, int r)
	{
		if (tr[u].l >= l and tr[u].r <= r) return tr[u];
		int mid = tr[u].l + tr[u].r >> 1;
		Node ans;
		ans.ll = -1;
		if (l <= mid) ans = query(u << 1, l, r);
		if (r > mid)
		{
			if (ans.ll == -1) ans = query(u << 1 | 1, l, r);
			else ans = ans + query(u << 1 | 1, l, r);
		}
		return ans;
	}
}t;

class Bit
{
public:
	long long tr[N];
	void add(int x, int v)
	{
		while (x < N)
		{
			tr[x] += 1LL * v;
			x += x & -x;
		}
	}
	long long query(int x)
	{
		long long ans = 0;
		while (x)
		{
			ans += tr[x];
			x -= x & -x;
		}
		return ans;
	}
}t2;

int cnt;

int main()
{
	// freopen("*.in", "r", stdin);
	// freopen("*.out", "w", stdout);
	//ios::sync_with_stdio(0), cin.tie(nullptr), cout.tie(nullptr);
	cin >> n >> s >> q;
	for (int i = 1; i <= n; i++)
	{
		a[i] = s[i - 1];
		t2.add(a[i], 1);
	}
	t.build(1, 1, n);
	for (int i = 1; i <= q; i++)
	{
		int op;
		cin >> op;
		if (op == 1)
		{
			int x;
			char c;
			cin >> x >> c;
			t.update(1, x, c);
			t2.add(a[x], -1);
			a[x] = c;
			t2.add(a[x], 1);
		}
		else
		{
			int l, r;
			cin >> l >> r;
			cnt++;
			a1[cnt] = t.query(1, l, r).is_as;
			if (!a1[cnt])
			{
				cout << "No\n";
				continue;
			}
			int ll = a[l] + 1;
			int rr = a[r] - 1;
			if (ll > rr) a2[cnt] = 1;
			else
			{
				int cnts = t2.query(rr) - t2.query(ll - 1);
				int lll = upper_bound(a + l, a + r + 1, a[l]) - a;
				int rrr = lower_bound(a + l, a + r + 1, a[r]) - 1 - a;
				if (cnts > rrr - lll + 1) a2[cnt] = 0;
				else a2[cnt] = 1;
			}
			if (a2[cnt] && a1[cnt]) cout << "Yes\n";
			else cout << "No\n";
		}
	}
	return 0;
}
posted @   HappyBobb  阅读(7)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示