https://www.luogu.org/problem/show?pid=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
将连续的没有交换的压缩成一个点
树状数组求逆序对
#include<cstdio> #include<algorithm> #define N 100001 using namespace std; int hashh[N<<1]; struct data { int turn,x,y; }g[N]; int dy2[N<<1]; struct node { int len,id; }e[N<<1]; int cnt,c[N<<1]; void add(int x,int y) { while(x<=cnt) { c[x]+=y; x+=x&-x; } } int query(int x) { int sum=0; while(x) { sum+=c[x]; x-=x&-x; } return sum; } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d",&g[i].x,&g[i].y); hashh[i*2-1]=g[i].x; hashh[i*2]=g[i].y; g[i].turn=i; } sort(hashh+1,hashh+n*2+1); int tot=unique(hashh+1,hashh+n*2+1)-(hashh+1); hashh[tot+1]=hashh[tot]+1; for(int i=1;i<=tot;i++) { if(hashh[i]+1==hashh[i+1]) { e[++cnt].id=cnt; e[cnt].len=hashh[i+1]-hashh[i]; dy2[i]=cnt; } else { e[++cnt].id=cnt; e[cnt].len=1; dy2[i]=cnt; e[++cnt].id=cnt; e[cnt].len=hashh[i+1]-hashh[i]-1; } } int a,b; for(int i=1;i<=n;i++) { a=lower_bound(hashh+1,hashh+tot+1,g[i].x)-hashh; b=lower_bound(hashh+1,hashh+tot+1,g[i].y)-hashh; a=dy2[a]; b=dy2[b]; swap(e[a],e[b]); } long long ans=0; for(int i=cnt;i;i--) { ans+=1ll*query(e[i].id)*e[i].len; add(e[i].id,e[i].len); } printf("%lld",ans); }
时间: 2024-10-10 00:31:15