洛谷2448 无尽的生命(树状数组)
2015-10-03 17:14
316 查看
题目描述
逝者如斯夫,不舍昼夜!叶良辰认为,他的寿命是无限长的,而且每天都会进步。
叶良辰的生命的第一天,他有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
思路:树状数组求逆序对。但是数据太大,直接做会超。于是,发现找区间的逆序对和点的逆序对之和就是所要求的答案。离散化一下,1、统计当前i(离散后的值)和i+1(同)的区间长度x*sum[ i ](i之后小于等于i的数),然后更新sum[ i ](+x),2、再统计点的逆序对(正常求法)。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #define ll long long using namespace std; const int maxn=2*100005; ll ans=0,ha[maxn],q1[maxn],q2[maxn],a[maxn],sum[maxn]; int n,p[maxn],t=0,cnt=0; inline int get(){ char c;while(!isdigit(c=getchar())); int v=c-48;while(isdigit(c=getchar()))v=v*10+c-48; return v; } inline int getpos(int x){ int l=1,r=cnt; while(l<r){ int mid=(l+r)>>1; if(x<=ha[mid])r=mid; else l=mid+1; } return l; } inline int lowbit(int x){return (x&(-x));} inline void add(int x,ll y){ while(x<=cnt){ sum[x]+=y; x+=lowbit(x); } } inline ll getsum(int x){ ll ret=0; while(x){ ret+=sum[x]; x-=lowbit(x); } return ret; } int main(){ n=get();memset(sum,0,sizeof(sum)); for(int i=1;i<=n;++i)a[++t]=q1[i]=get(),a[++t]=q2[i]=get(); sort(a+1,a+1+t); for(int i=1;i<=t;++i)if(a[i]!=a[i-1])ha[++cnt]=a[i]; for(int i=1;i<=cnt;++i)p[i]=i; for(int i=1;i<=n;++i){ int x=getpos(q1[i]),y=getpos(q2[i]); int tt=p[x];p[x]=p[y];p[y]=tt; } add(p[cnt],1); for(int i=cnt-1;i>=1;--i){ ll x=(ha[i+1]-ha[i]-1),y=getsum(i); ans+=x*y; add(i,x); ans+=getsum(p[i]-1); add(p[i],1); } printf("%lld\n",ans); return 0; }
相关文章推荐
- Linux 命令 - chmod: 更改文件模式
- pat1018Public Bike Management (30)
- 堆栈之表达式求值
- 如何打开USB OTG功能:
- 各种二分查找算法总结
- 书籍共享
- C++实现复数类(重载操作符实现复数对应的操作)
- SSD阵列卡方案优化:考虑使用RAID 50替代RAID 10
- 安卓控件使用系列26:ImageSwitcher图片切换控件的使用方法
- 关于public static void main(string[] args)的典故
- git ignore 文件配置
- PAT 1033. To Fill or Not to Fill (25)
- FZU 1759-Super A^B mod C(指数循环节)
- scrollTo/scrollBy方法和手势监听器的使用
- UML概述
- 炮兵阵地 - POJ 1185(状态压缩)
- 二维数组的初始化
- 每日三个笑话-20151003
- VTK6.2编译+Qt5.5
- ZOJ-3900-Three Circles