题解:P9757 [COCI2022-2023#3] Dirigent
分析
设 \(a[i]\) 为第 \(i\) 位的人的编号,\(\operatorname{pre}(i)\) 为第 \(i\) 位前一个的人。
记 \(cnt\) 为满足 \(a[\operatorname{pre}(i)]+1=a[i]\) 的 \(i\) 的个数。
显然当 \(cnt=n-1\) 时,满足题目条件。
我们可以在一开始预先 \(O(n)\) 处理出 \(cnt\)。
考虑一次交换操作带来的贡献。
对于任意一个人,可以 \(O(1)\) 算出他和他前后的人产生的贡献。
所以 \(O(1)\) 算出要交换的人 \(x\) 和 \(y\) 的贡献,将 \(cnt\) 减去原贡献后再加上新的贡献。
但是如果 \(x\) 和 \(y\) 相邻,可能会有错误的贡献,这时需要特判。
Code
#include<bits/stdc++.h>
using namespace std;
#define maxn 300005
int a[maxn], pos[maxn];
#define pre(i) (((i)==1)?(n):((i)-1))
#define nxt(i) (((i)==n)?(1):((i)+1))
#define chkpre(x) (a[x]==a[pre(x)]+1)
#define chknxt(x) (a[x]+1==a[nxt(x)])
int main()
{
int n, q, x, y;
cin>>n>>q;
int cnt=0;
for(int i=1;i<=n;i++) cin>>a[i], pos[a[i]]=i;
for(int i=1;i<=n;i++)
if(a[i]==a[pre(i)]+1) cnt++;
while(q--)
{
cin>>x>>y;
if(pre(x)==y) swap(x, y);
int nx=x, ny=y;
x=pos[x], y=pos[y];
cnt-=chkpre(x)+chknxt(x)+chkpre(y)+chknxt(y);
if(nxt(x)==y&&a[x]+1==a[y]) cnt++;
swap(a[x], a[y]);
swap(pos[nx], pos[ny]);
cnt+=chkpre(x)+chknxt(x)+chkpre(y)+chknxt(y);
swap(x, y);
if(nxt(x)==y&&a[x]+1==a[y]) cnt--;
cout<<(cnt==n-1?"DA":"NE")<<'\n';
}
}

浙公网安备 33010602011771号