P1503 鬼子进村

链接

https://www.luogu.com.cn/problem/P1503

思路

树状数组。本来的想法是由于删掉了某个村庄,那么可以统一修改左边村庄的右边界为x-1;右边村庄的左边界为x+1;但是要用到两棵可持久化线段树。
所以想到:直接对某个节点设0/1状态。被毁了就设置成0,然后两次二分统计区间和满足条件的最大长度即可。

代码

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define int long long
const int N = 5e4 + 10;
int lowbit(int x) { return x & (-x); }
int tree[N];

void add(int x, int t)
{
	while (x < N)
	{
		tree[x] += t;
		x += lowbit(x);
	}
	return;
}
int sum(int x)
{
	int a = 0;
	while (x > 0)
	{
		a += tree[x];
		x -= lowbit(x);
	}
	return a;
}
void solve()
{
	stack<int>st;
	int n, m; cin >> n >> m;
	for (int i = 1; i <= n; i++)add(i, 1);
	for (int i = 0; i < m; i++)
	{
		char d; int x;
		cin >> d;
		if (d == 'D')
		{
			cin >> x;
			st.push(x);
			add(x, -1);
		}
		else if (d == 'Q')
		{
			cin >> x;
			if (sum(x)-sum(x-1) == 0)cout << 0 << '\n';
			else
			{
				int L, R;
				int l = 1; int r = x - 1;
				while (l <= r)
				{
					int m = (l + r) >> 1;
					if (sum(r) - sum(m - 1) == r - m + 1)
					{
						r = m - 1;
					}
					else l = m + 1;
				}
				L = l;
				l = x , r = n;
				while (l < r)
				{
					int m = (l + r + 1) >> 1;
					if (sum(m) - sum(l - 1) == m - l + 1)l = m;
					else r = m - 1;
				}
				R = l;
				cout << R - L + 1 << '\n';
			}
		}
		else {
			int now = st.top();
			st.pop();
			add(now, 1);
		}
	}

}

signed main()
{
	IOS;
	solve();
	return 0;
}




posted @ 2025-03-19 16:36  WHUStar  阅读(21)  评论(0)    收藏  举报