P2448 无尽的生命
题意
一个很长的序列 ,值分别是 。
进行 个操作,每次有两个数 ,请交换 ,最后输出新序列的逆序对数。
分析
每次交换只会改变两个数的位置,交换的次数也比较少,于是我们可以根据 把整个序列分成几段,每段内的数字都是连续的。
请看下面的例子:
2
1 8
4 10
交换的点 显然要单独一段,中间的数也要一段。
这样就知道怎么分了吧,所有作为左端点的数就是 ,将他们放进数组 中进行排序并去重,确定每个区间的左端点,右端点就是下一个区间的左端点减 。虽然这样看起来像是离散化,但其实并不是。交换时只要交换 所在的段即可。
for(int i=1;i<=n;i++){
x[i]=read();y[i]=read();
c[++m]=x[i];c[++m]=x[i]+1;
c[++m]=y[i];c[++m]=y[i]+1;
}
sort(c+1,c+m+1);
int tot=unique(c+1,c+m+1)-c-1;
for(int i=1;i<tot;i++)
a[i].l=c[i],a[i].r=c[i+1]-1;
for(int i=1;i<=n;i++){
x[i]=lower_bound(c+1,c+tot+1,x[i])-c;
y[i]=lower_bound(c+1,c+tot+1,y[i])-c;
swap(a[x[i]],a[y[i]]);
}
接下来就是求逆序对了。
按照套路,倒序扫描。
然后我们需要实现:
-
求一段区间中少于某个数的数的个数——区间查询。
-
把一段连续的数出现的次数增加 ——区间增加。
这不就是线段树吗!
于是我们可以以权值为节点建一棵线段树。
然而叶子节点数多达 ,普通线段树是存不下的,所以我们用动态开点的线段树就可以了。
每次求答案记得要乘上区间的长度。
最后就是动态开点权值线段树板子了。
友情提示:要开 long long,动态开点线段树空间要开大。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll read(){
ll x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void write(ll x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int N=1e5+10,M=3e6+10;
int n,m,c[N<<2],x[N],y[N],t=1,l,r;
ll ans;
struct qj{
int l,r;
}a[N<<2];
struct Tree{
int cl,cr;
ll tag,sum;
}s[M];
void make(int p){
if(s[p].cl)
return;
s[p].cl=++t;s[p].cr=++t;
}
void pushup(int p){
s[p].sum=s[s[p].cl].sum+s[s[p].cr].sum;
}
void pushdown(int p,int l,int mid,int r){
if(s[p].tag){
s[s[p].cl].tag=s[s[p].cr].tag=s[p].tag;
s[s[p].cl].sum+=s[p].tag*(mid-l+1);
s[s[p].cr].sum+=s[p].tag*(r-mid);
s[p].tag=0;
}
}
void add(int p,int l1,int r1){
if(l<=l1&&r1<=r){
s[p].tag++;
s[p].sum+=(r1-l1+1);
return;
}
int mid=(l1+r1)>>1;
make(p);
pushdown(p,l1,mid,r1);
if(l<=mid)
add(s[p].cl,l1,mid);
if(r>mid)
add(s[p].cr,mid+1,r1);
pushup(p);
}
ll ask(int p,int l1,int r1){
if(l<=l1&&r1<=r)
return s[p].sum;
ll ans=0;
int mid=(l1+r1)>>1;
make(p);
pushdown(p,l1,mid,r1);
if(l<=mid)
ans+=ask(s[p].cl,l1,mid);
if(r>mid)
ans+=ask(s[p].cr,mid+1,r1);
return ans;
}
int main()
{
n=read();
for(int i=1;i<=n;i++){
x[i]=read();y[i]=read();
c[++m]=x[i];c[++m]=x[i]+1;
c[++m]=y[i];c[++m]=y[i]+1;
}
sort(c+1,c+m+1);
int tot=unique(c+1,c+m+1)-c-1;
for(int i=1;i<tot;i++)
a[i].l=c[i],a[i].r=c[i+1]-1;
for(int i=1;i<=n;i++){
x[i]=lower_bound(c+1,c+tot+1,x[i])-c;
y[i]=lower_bound(c+1,c+tot+1,y[i])-c;
swap(a[x[i]],a[y[i]]);
}
for(int i=tot-1;i;i--){
l=1;r=a[i].l-1;
if(l<=r)
ans+=ask(1,1,c[tot])*(a[i].r-a[i].l+1);
l=a[i].l,r=a[i].r;
add(1,1,c[tot]);
}
write(ans);
return 0;
}

浙公网安备 33010602011771号