Field Should Not Be Empty

这道题目的思想非常新

首先我们按照比较传统的想法,考虑交换两个位置ij能带来什么影响

然后这就是这道题目的精华所在了,我们考虑影响的时候,没有必要去精确每一个位置的两个信息(左边更大的数的个数和右边更小的数的个数)怎么样变化,而是只用考虑这一次交换会让答案增大多少(其实重新做这道题目的时候就是这么想的,所以以后的只修改一次的题目就可以从这两个方向去想)

我们先考虑(i,j),不难发现,如果某一个数(设为x)左边恰好有一个数比其大,右边恰好有一个数比其小,而且恰好分别对应下标ij,那么x就会对i,j的交换产生一个贡献

再考虑ij是否会产生贡献,比如i,显然只有将i交换到下标pi时才会产生贡献

而在区间[i,j]外面的都不用考虑

代码见下

#include<bits/stdc++.h>
#define ll long long
#define ULL unsigned long long
using namespace std;
const int N=2e5+10;
int n;
int f[N][2],mx[N][3];
//f[i][0]表示第i个数前面唯一一个大于其的数
//f[i][1]表示第i个数后面唯一一个小于其的数
vector<int> G[N]; 
int c[N];
int segmax[N<<2],lazy[N<<2];
int p[N],pos[N],vis[N];
//pos[i]表示i的下标,vis用来判断数在原序列中是否是good,如果为2则代表为good 
void add(int x)
{
	for(;x<=n;x+=x&-x) c[x]++;
}
int ask(int x)
{
	int res=0;
	for(;x>=1;x-=x&-x) res+=c[x];
	return res;
}
void build(int p,int l,int r)
{
	if(l==r)
	{
		segmax[p]=lazy[p]=0;
		return;
	}
	int mid=l+r>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	segmax[p]=lazy[p]=0; 
}
void pushdown(int p)
{
	segmax[p<<1]+=lazy[p],lazy[p<<1]+=lazy[p];
	segmax[p<<1|1]+=lazy[p],lazy[p<<1|1]+=lazy[p];
	lazy[p]=0;
}
void modify(int p,int l,int r,int x,int d)
{
	if(l>x||r<x) return;
	if(l==r)
	{
		segmax[p]+=d;
		return ;
	}
	if(lazy[p]) pushdown(p);
	int mid=l+r>>1;
	modify(p<<1,l,mid,x,d);
	modify(p<<1|1,mid+1,r,x,d);
	segmax[p]=max(segmax[p<<1],segmax[p<<1|1]);
}
void modify1(int p,int l,int r,int x,int y,int d)
{
	if(l>y||r<x) return;
	if(l>=x&&r<=y)
	{
		segmax[p]+=d;
		lazy[p]+=d;
		return;
	}
	if(lazy[p]) pushdown(p);
	int mid=l+r>>1;
	modify1(p<<1,l,mid,x,y,d);
	modify1(p<<1|1,mid+1,r,x,y,d);
	segmax[p]=max(segmax[p<<1],segmax[p<<1|1]);
}
int getmax(int p,int l,int r,int x,int y)
{
	if(l>y||r<x) return -0x7fffffff;
	if(l>=x&&r<=y) return segmax[p];
	if(lazy[p]) pushdown(p);
	int mid=l+r>>1;
	return max(getmax(p<<1,l,mid,x,y),getmax(p<<1|1,mid+1,r,x,y));
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		for(int j=0;j<=1;j++)
		f[i][j]=0;
		for(int i=1;i<=n;i++)
		G[i].clear(),c[i]=vis[i]=0;
		build(1,1,n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&p[i]);
			pos[p[i]]=i;
		 } 
		mx[1][0]=p[1],mx[n][1]=p[n];
		for(int i=2;i<=n;i++) mx[i][0]=max(mx[i-1][0],p[i]);
		for(int i=n-1;i>=1;i--) mx[i][1]=min(mx[i+1][1],p[i]);
		for(int i=1;i<=n;i++)
		{
			int u=ask(n)-ask(p[i]);//这里一定要用树状数组判断
			//否则边界情况讨论太麻烦了 
			if(u==1) f[i][0]=mx[i-1][0];
			else if(!u) vis[i]++;
			add(p[i]);	
		}
		for(int i=1;i<=n;i++) c[i]=0;
		for(int i=n;i>=1;i--)
		{
			int u=ask(p[i]-1);
			if(u==1) f[i][1]=mx[i+1][1];
			else if(!u) vis[i]++;
			add(p[i]);
		}
		int sum=0,Max=-0x7fffffff;
		for(int i=1;i<=n;i++)
		if(vis[i]==2) sum++;
		else if(f[i][0]&&f[i][1]) G[pos[f[i][1]]].push_back(pos[f[i][0]]);
		for(int i=1;i<=n;i++)
		{
			for(int j=0;j<G[i].size();j++)
			{
				int u=G[i][j];
				modify(1,1,n,u,1);
			} 
			if(p[i]<i&&(i==1||mx[p[i]-1][0]==p[i]-1))
			modify(1,1,n,p[i],1);
			else if(vis[i]==2) modify1(1,1,n,1,i-1,-1);
			if(pos[i]<i&&(i==n||mx[i+1][1]==i+1))
			modify(1,1,n,pos[i],1);
			else if(vis[pos[i]]==2) modify(1,1,n,pos[i],-1);
			if(i>1) Max=max(Max,getmax(1,1,n,1,i-1));
			for(int j=0;j<G[i].size();j++)
			{
				int u=G[i][j];
				modify(1,1,n,u,-1);
			} 
			if(p[i]<i&&(i==1||mx[p[i]-1][0]==p[i]-1))
			modify(1,1,n,p[i],-1);
			else if(vis[i]==2) modify1(1,1,n,1,i-1,1);
			if(pos[i]<i&&(i==n||mx[i+1][1]==i+1))
			modify(1,1,n,pos[i],-1);
			else if(vis[pos[i]]==2) modify(1,1,n,pos[i],1);
			if(vis[i]==2) modify1(1,1,n,1,i,-1);
		}
		printf("%d\n",sum+Max);
	}
	return 0;
}
posted @   最爱丁珰  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示