生日礼物 解题报告
简要题意
给定一个长度为 \(n\) 的数组 \(a\),初始时满足 \(\forall_{1\le i \le n}a_i=i\)。有 \(m\) 次操作,每一次操作都会把一个数 \(x\) 移动到另一个数 \(y\) 的前面或后面。
询问所有操作后,通过上述操作将数组恢复为操作前的最小操作次数。
其中 \(n\le 5 \times 10^5,m \le 10^5\)
分析
删除一个元素数,在一个元素前插入元素,不需要随机访问,看来是链表。
考虑询问怎么做。
结论:最小操作次数等于数组长度减去操作后数组的 LIS。
证明:
首先一个元素只会被操作一次。(如果有多次操作,那完全可以只做最后一次)
显然不需要操作的元素越多越好,那么我们考虑不需要操作的元素有什么特点。
由于开始时的数组时是一个上升序列,那么不需要操作的元素显然也构成上升序列。
因此当不需要操作的元素为数组中LIS的元素时,操作次数最小。
Q.E.D.
然后二分法求 LIS 即可。
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define Inf (1ll<<60)
#define For(i,s,t) for(int i=s;i<=t;++i)
#define Down(i,s,t) for(int i=s;i>=t;--i)
#define ls (i<<1)
#define rs (i<<1|1)
#define bmod(x) ((x)>=mod?(x)-mod:(x))
#define lowbit(x) ((x)&(-(x)))
#define End {printf("NO\n");exit(0);}
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
inline void ckmx(int &x,int y){x=(x>y)?x:y;}
inline void ckmn(int &x,int y){x=(x<y)?x:y;}
inline void ckmx(ll &x,ll y){x=(x>y)?x:y;}
inline void ckmn(ll &x,ll y){x=(x<y)?x:y;}
inline int min(int x,int y){return x<y?x:y;}
inline int max(int x,int y){return x>y?x:y;}
inline ll min(ll x,ll y){return x<y?x:y;}
inline ll max(ll x,ll y){return x>y?x:y;}
inline int read(){
register int x=0,f=1;
char c=getchar();
while(c<'0' || '9'<c) f=(c=='-')?-1:1,c=getchar();
while('0'<=c && c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
return x*f;
}
void write(int x){
if(x>=10) write(x/10);
putchar(x%10+'0');
}
const int N=5e5+100;
int n,m,pre[N],suf[N],a[N],f[N];
char s[5];
int main()
{
freopen("lista.in","r",stdin);
freopen("lista.out","w",stdout);
n=read(),m=read();
For(i,1,n) pre[i]=i-1,suf[i]=i+1;
suf[0]=1,pre[n+1]=n;
int x,y;
For(i,1,m){
scanf("%s",s+1);
x=read(),y=read();
pre[suf[x]]=pre[x];
suf[pre[x]]=suf[x];
if(s[1]=='A'){
pre[x]=pre[y],suf[pre[y]]=x;
suf[x]=y,pre[y]=x;
}
else{
suf[x]=suf[y],pre[suf[y]]=x;
pre[x]=y,suf[y]=x;
}
}
int ans=1,u=0,cur=1,len=0;
For(i,1,n) u=suf[u],a[i]=u;
f[0]=0;
For(i,1,n){
if(a[i]>f[len])
f[++len]=a[i];
else{
int L=1,R=len,mid,res=0;
while(L<=R){
mid=L+R>>1;
if(f[mid]<a[i])
res=mid,L=mid+1;
else
R=mid-1;
}
ckmn(f[res+1],a[i]);
}
}
printf("%d",n-len);
return 0;
}