交换 题解
http://www.nfls.com.cn:10688/contest/369/problem/2
现在回看这道题,并没有想象的那么难了
非常显然的,因为是字典序,所以肯定是越靠前的位置越小越好。所以可以找出这一段区间从开头开始的最长连续上升段,那么交换的一定是连续上升段和连续上升段后的数字。求出连续上升段后的最小值,然后找到连续上升段中第一个比这个最小值大的位置,交换这两个位置就是最优的。
求连续上升段可以给每个位置维护一个标记,表示这个位置是否比下一个位置大。用线段树二分查找第一个有标记的位置就可以找到最长连续上升段,线段树还要维护最小值,查询连续上升段中第一个比最小值大的位置,可以用线段树维护最大值,二分查找得到
代码参考yyh,他写的十分精简,把维护连续上升段和最小值放在一起处理了,因为最小值一定要在连续上升段的后面,所以query时先右子树再左子树,相当于就是把最小值从右往左逼近
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=4e6+5;
const int inf=0x3f3f3f3f;
int n,m;
int a[maxn],A,B,minv;
int mn[maxn],mx[maxn],flg[maxn];
void push_up(int rt)
{
if(a[mn[rt<<1]]<a[mn[rt<<1|1]])
mn[rt]=mn[rt<<1];
else
mn[rt]=mn[rt<<1|1];
if(a[mx[rt<<1]]>a[mx[rt<<1|1]])
mx[rt]=mx[rt<<1];
else
mx[rt]=mx[rt<<1|1];
flg[rt]=flg[rt<<1]|flg[rt<<1|1];
if(a[mx[rt<<1]]>a[mn[rt<<1|1]])
flg[rt]=1;
}
void build(int rt,int l,int r)
{
if(l==r)
{
mn[rt]=l;
mx[rt]=l;
return ;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
push_up(rt);
}
void update(int rt,int l,int r,int x)
{
if(l==r)
return ;
int mid=(l+r)>>1;
if(x<=mid)
update(rt<<1,l,mid,x);
else
update(rt<<1|1,mid+1,r,x);
push_up(rt);
}
void ask(int rt,int l,int r,int x)
{
if(l==r)
{
if(a[x]<a[l])
{
A=l;
B=x;
return ;
}
return ;
}
int mid=(l+r)>>1;
if(min(a[x],a[mn[rt<<1|1]])<a[mx[rt<<1]]||flg[rt<<1])
ask(rt<<1,l,mid,a[mn[rt<<1|1]]<a[x]?mn[rt<<1|1]:x);
else
ask(rt<<1|1,mid+1,r,x);
}
void query(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
ask(rt,l,r,minv);
if(a[mn[rt]]<a[minv])
minv=mn[rt];
return ;
}
int mid=(l+r)>>1;
if(R>mid)
query(rt<<1|1,mid+1,r,L,R);
if(L<=mid)
query(rt<<1,l,mid,L,R);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
freopen("swap.in","r",stdin);
freopen("swap.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
a[0]=inf;
build(1,1,n);
while(m--)
{
int l,r;
cin>>l>>r;
A=-1;B=-1;
minv=0;
query(1,1,n,l,r);
if(A==-1)
{
cout<<"-1"<<"\n";
continue;
}
else
{
swap(a[A],a[B]);
update(1,1,n,A);
update(1,1,n,B);
cout<<A<<" "<<B<<"\n";
}
}
return 0;
}
标签:rt,int,交换,最小值,maxn,连续,上升段 来源: https://www.cnblogs.com/zxi8-may/p/16300766.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。