Luogu P2448 无尽的生命 题解
双倍经验:CF540E
题意简述
给定一个数列 \(1,2,3\dots n\) 和 \(k\) 次操作,每次操作交换数列中下标为 \(x\) 和 \(y\) 的数。求最终数列中有多少个逆序对。其中 $ n,x,y\le 2^{31}-1, k\le 10^5 $。
前置知识
树状数组,离散化
Solution
显然可以用树状数组求逆序对。但是难点在于原数列中可能有很多元素没有被交换过,要考虑怎么计算它们的贡献。
注意到操作数 \(k\le10^5\),因此最多只有 \(2\times10^5\) 个数被交换了。这样,最多会产生 \(2\times10^5-1\) 个区间,处于这些区间之间的数都没有被交换过。设区间 \([l,r]\) 中的所有元素都没有被交换过,显然这些数两两之间都不可能产生逆序对,因此考虑用任意一个 \(x\in[l,r]\) 代替这些数,并将 \(x\) 的权值设为 \(r-l+1\) 。对于交换过的数,权值设为 \(1\) 即可。这样一来,我们就得到了一个新的序列,这个序列仅有不超过 \(4\times10^5-1\) 个数,离散化之后就可以使用权值树状数组来求逆序对了。注意对于每个 \(x\) 统计贡献时要乘上 \(x\) 的权值。
时间复杂度 \(O(k \log{k})\)。
Code
#include<bits/stdc++.h>
#define int long long
#define lowbit(x) x&-x
#define INF 0x7fffffff
using namespace std;
const int N=1e6+10;
struct node{int x,y;}t[N];
int n;
int a[N],b[N],c[N];
void add(int x,int k) {while(x<=n) c[x]+=k,x+=lowbit(x);}
int get_sum(int x) {int res=0;while(x>=1) res+=c[x],x-=lowbit(x);return res;}
int s[N],siz[N];//siz[x]表示x的权值
signed main()
{
int k;
scanf("%lld",&k);
for(int i=1;i<=k;i++)
scanf("%lld%lld",&t[i].x,&t[i].y),
a[i*2-1]=t[i].x,a[i*2]=t[i].y;
memcpy(b,a,sizeof(b));
sort(b+1,b+2*k+1);
n=unique(b+1,b+2*k+1)-b-1;
for(int i=1;i<=n;i++) a[i*2-1]=b[i];
n=n*2-1;
for(int i=1;i<=n;i++)
{
if(i&1) continue;
if(a[i+1]==a[i-1]+1) a[i]=INF;
else a[i]=a[i-1]+1,s[i]=a[i+1]-a[i-1]-1;
}
memcpy(b,a,sizeof(b));
sort(a+1,a+n+1);
int tmp=n;
while(a[n]==INF) n--;
for(int i=1;i<=tmp;i++)
{
if(b[i]==INF) continue;
int idx=lower_bound(a+1,a+n+1,b[i])-a;
siz[idx]=s[i];
}
for(int i=1;i<=n;i++) if(!siz[i]) siz[i]=1;
memcpy(b,a,sizeof(b));
for(int i=1;i<=k;i++)
{
int idx=lower_bound(b+1,b+n+1,t[i].x)-b;
int idy=lower_bound(b+1,b+n+1,t[i].y)-b;
swap(a[idx],a[idy]);
}
int ans=0;
for(int i=n;i>=1;i--)
{
int idx=lower_bound(b+1,b+n+1,a[i])-b;
ans+=siz[i]*get_sum(idx-1);
add(idx,siz[i]);
}
printf("%lld\n",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现