CF1270H. Number of Components

题目大意

ij之间有边当且仅当i<j且a[i]<a[j],动态修改a,求连通块个数

题解

线段树吼题

转换一:把求连通块个数变成求分界线个数

设a[0]=inf,a[n+1]=-inf

分界线的定义:min(a[1...i])>max(a[i+1...n])

转换二:设h[i][j]=[a[j]>a[i]],则点i的a[i]能把图分成两块当且仅当h[i]中前面一段是1,后面一段是0

手玩一下即可,刚好可以按十字分成左上和右下

于是变成维护有多少个i满足h[i]只有两段,等于维护h[a[i]]中 10子串 个数

直接维护所有h[i],同时维护i是否存在,修改只与a[x-1]、a[x]、a[x+1]和y有关(影响是一段区间)

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define ll long long
#define N 1000000
//#define file
using namespace std;

int tr[4000001][2],Tr[4000001],a[500002],n,Q,i,j,k,l,x,y;

void down(int t,int len)
{
	if (Tr[t])
	{
		if (len>1) Tr[t*2]+=Tr[t],Tr[t*2+1]+=Tr[t];
		tr[t][0]+=Tr[t];
		Tr[t]=0;
	}
}
void up(int t)
{
	if (tr[t*2][0]<tr[t*2+1][0])
	tr[t][0]=tr[t*2][0],tr[t][1]=tr[t*2][1];
	else
	if (tr[t*2][0]>tr[t*2+1][0])
	tr[t][0]=tr[t*2+1][0],tr[t][1]=tr[t*2+1][1];
	else
	tr[t][0]=tr[t*2][0],tr[t][1]=tr[t*2][1]+tr[t*2+1][1];
}

void change(int t,int l,int r,int x,int y,int s)
{
	x=max(x,1);y=min(y,N);
	if (x>y) return;
	
	int mid=(l+r)/2;
	down(t,r-l+1);
	if (x<=l && r<=y) {Tr[t]+=s;down(t,r-l+1);return;}
	
	down(t*2,mid-l+1);down(t*2+1,r-mid);
	if (x<=mid) change(t*2,l,mid,x,y,s);
	if (mid<y) change(t*2+1,mid+1,r,x,y,s);
	
	up(t);
}
void Change(int t,int l,int r,int x,int s)
{
	int mid=(l+r)/2;
	down(t,r-l+1);
	if (l==r) {tr[t][1]+=s;return;}
	
	down(t*2,mid-l+1);down(t*2+1,r-mid);
	if (x<=mid) Change(t*2,l,mid,x,s);
	else Change(t*2+1,mid+1,r,x,s);
	
	up(t);
}

int main()
{
	#ifdef file
	freopen("CF1270H.in","r",stdin);
	#endif
	
	scanf("%d%d",&n,&Q);
	a[0]=1919810;a[n+1]=-1919810;
	fo(i,1,n) scanf("%d",&a[i]),Change(1,1,N,a[i],1);
	fo(i,0,n) if (a[i]>a[i+1]) change(1,1,N,a[i+1],a[i]-1,1);
	
	for (;Q;--Q)
	{
		scanf("%d%d",&x,&y);
		Change(1,1,N,a[x],-1);
		if (a[x-1]>a[x]) change(1,1,N,a[x],a[x-1]-1,-1);
		if (a[x]>a[x+1]) change(1,1,N,a[x+1],a[x]-1,-1);
		a[x]=y;
		Change(1,1,N,a[x],1);
		if (a[x-1]>a[x]) change(1,1,N,a[x],a[x-1]-1,1);
		if (a[x]>a[x+1]) change(1,1,N,a[x+1],a[x]-1,1);
		
		printf("%d\n",tr[1][1]);
	}
	
	fclose(stdin);
	fclose(stdout);
	
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/gmh77/p/12799338.html