洛谷2448 无尽的生命[树状数组 离散化]

题目描述

逝者如斯夫,不舍昼夜!

叶良辰认为,他的寿命是无限长的,而且每天都会进步。

叶良辰的生命的第一天,他有1点能力值。第二天,有2点。第n天,就有n点。也就是S[i]=i

但是调皮的小A使用时光机,告诉他第x天和第y天,就可以任意交换某两天的能力值。即S[x]<-->S[y]

小A玩啊玩,终于玩腻了。

叶良辰:小A你给我等着,我有100种办法让你生不如死。除非能在1秒钟之内告知有多少对“异常对”。也就是说,最后的能力值序列,有多少对的两天x,y,其中x<y,但是能力值S[x]>S[y]?

小A:我好怕怕啊。

于是找到了你。

输入输出格式

输入格式:

 

第一行一个整数k,表示小A玩了多少次时光机

接下来k行,x_i,y_i,表示将S[x_i]与S[y_i]进行交换

 

输出格式:

 

有多少“异常对”

 

输入输出样例

输入样例#1:
2
4 2
1 4
输出样例#1:
4

说明

样例说明

最开始是1 2 3 4 5 6...

然后是 1 4 3 2 5 6...

然后是 2 4 3 1 5 6...

符合的对是[1 4] [2 3] [2 4] [3 4]

对于30%的数据,x_i,y_i <= 2000

对于70%的数据, x_i,y_i <= 100000

对于100%的数据, x_i.y_i <= 2^31-1 k<=100000


 

本来以为很简单,结果并不是

排序去重做离散化交换过的点

a是离散化后能力值序列,按顺序交换a值

然后BIT求逆序对,倒着处理比较好

注意有两块,一块是离散后的“端点”,一块是两个端点之间的数值mp[i+1]-mp[i]-1;

 

 

//
//  main.cpp
//  luogu2448
//
//  Created by Candy on 21/10/2016.
//  Copyright © 2016 Candy. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
const int N=1e5+5;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
struct data{
    int x,y;
}q[N];
int n,m,mp[N],t[N],a[N],c[N];
inline int Bin(int x){
    int l=1,r=m;
    while(l<=r){
        int m=(l+r)/2;
        if(mp[m]==x) return m;
        else if(mp[m]>x) r=m-1;
        else l=m+1;
    }
    return l;
}
inline int lowbit(int x){return x&-x;}
inline void add(int p,int v){
    for(int i=p;i<=m;i+=lowbit(i)) c[i]+=v;
}
inline int sum(int p){
    int res=0;
    for(int i=p;i>0;i-=lowbit(i)) res+=c[i];
    return res;
}
ll solve(){
    ll ans=0;
    add(a[m],1);
    for(int i=m-1;i>=1;i--){
        int len=mp[i+1]-mp[i]-1;
        ans+=len*sum(i);
        add(i,len);
        
        ans+=sum(a[i]-1);
        add(a[i],1);
    }
    return ans;
}
int main(int argc, const char * argv[]) {
    n=read();
    for(int i=1;i<=n;i++){
        t[2*i-1]=q[i].x=read();
        t[2*i]=q[i].y=read();
    }
    n*=2;
    sort(t+1,t+1+n);
    t[0]=-1;
    for(int i=1;i<=n;i++) if(t[i]!=t[i-1]) mp[++m]=t[i];
    for(int i=1;i<=m;i++) a[i]=i;
    for(int i=1;i<=n/2;i++){
        int x=Bin(q[i].x),y=Bin(q[i].y);//printf("q %d %d\n",x,y);
        swap(a[x],a[y]);
    }
    printf("%lld",solve());
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值