Field Should Not Be Empty
这道题目的思想非常新
首先我们按照比较传统的想法,考虑交换两个位置
然后这就是这道题目的精华所在了,我们考虑影响的时候,没有必要去精确每一个位置的两个信息(左边更大的数的个数和右边更小的数的个数)怎么样变化,而是只用考虑这一次交换会让答案增大多少(其实重新做这道题目的时候就是这么想的,所以以后的只修改一次的题目就可以从这两个方向去想)
我们先考虑
再考虑
而在区间
代码见下
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构