生日礼物 解题报告

简要题意

给定一个长度为 \(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;
}
posted @ 2025-08-10 12:31  XiaoZi_qwq  阅读(5)  评论(0)    收藏  举报