1. 程式人生 > 實用技巧 >NOIP2020.9.19模擬patrick

NOIP2020.9.19模擬patrick

題目大意

動態維護數列中大於等於某個數的極長連續段的個數。

解題思路

\(Code\)

#include<cstdio>
using namespace std;
long long f[2000005],a[500005],tag[2000005],ans,n,m;

void pushdown(int l,int r,int k)
{
	if (!tag[k]) return;
	int mid = l + r >> 1;
	tag[k << 1] += tag[k];
	tag[k << 1 | 1] += tag[k];
	f[k << 1] += tag[k] * (mid - l + 1);
	f[k << 1 | 1] += tag[k] * (r - mid);
	tag[k] = 0;
}
void change(int l,int r,int k,int L,int R,int u)
{
	if (r < L && l > R) return;
	if (l >= L && r <= R)
	{
		f[k] += u * (r - l + 1);
		tag[k] += u;
		return;
	}
	pushdown(l,r,k);
	int mid = l + r >> 1;
	if (L <= mid) change(l,mid,k << 1,L,R,u);
	if (R > mid) change(mid + 1,r,k << 1 | 1,L,R,u);
	f[k] = f[k << 1] + f[k << 1 | 1];
}
int query(int l,int r,int k,int u)
{
	if (l == r && l == u) return f[k];
	pushdown(l,r,k);
	int mid = l + r >> 1;
	if (u <= mid) return query(l,mid,k << 1,u);
	else return query(mid + 1,r,k << 1 | 1,u);
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i = 1; i <= n; i++)
	{
		scanf("%d",&a[i]);
		if (a[i] > 500000) a[i] = 500000;
		if (a[i] > a[i - 1]) change(1,500000,1,a[i - 1] + 1,a[i],1);
	}
	char s[5];
	int lst = 0;
	for (int i = 1; i <= m; i++)
	{
		int q,p;
		scanf("%s",s);
		if (s[0] == 'Q')
		{
			scanf("%d",&q);
			q = q ^ lst;
			lst = query(1,500000,1,q);
			printf("%d\n",lst);	
		}
		else
		{
			scanf("%d%d",&q,&p);
			q = q ^ lst,p = p ^ lst;
			if (a[q] < a[q + 1]) change(1,500000,1,a[q] + 1,a[q + 1],-1);
			if (p < a[q + 1]) change(1,500000,1,p + 1,a[q + 1],1);
			if (a[q] > a[q - 1]) change(1,500000,1,a[q - 1] + 1,a[q],-1);
			if (p > a[q - 1]) change(1,500000,1,a[q - 1] + 1,p,1);
			a[q] = p;
		}
	}
}