bzoj 2141: 排队
2141: 排队
Description
排排坐,吃果果,生果甜嗦嗦,大家笑呵呵。你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和。红星幼儿园的小朋友们排起了长长地队伍,准备吃果果。不过因为小朋友们的身高有所区别,排成的队伍高低错乱,极不美观。设第i个小朋友的身高为hi,我们定义一个序列的杂乱程度为:满足ihj的(i,j)数量。幼儿园阿姨每次会选出两个小朋友,交换他们的位置,请你帮忙计算出每次交换后,序列的杂乱程度。为方便幼儿园阿姨统计,在未进行任何交换操作时,你也应该输出该序列的杂乱程度。
Input
第一行为一个正整数n,表示小朋友的数量;第二行包含n个由空格分隔的正整数h1,h2,…,hn,依次表示初始队列中小朋友的身高;第三行为一个正整数m,表示交换操作的次数;以下m行每行包含两个正整数ai和bi¬,表示交换位置ai与位置bi的小朋友。
Output
输出文件共m行,第i行一个正整数表示交换操作i结束后,序列的杂乱程度。
Sample Input
【样例输入】
3
130 150 140
2
2 3
1 3
130 150 140
2
2 3
1 3
Sample Output
1
0
3
【样例说明】
未进行任何操作时,(2,3)满足条件;
操作1结束后,序列为130 140 150,不存在满足i<j且hi>hj的(i,j)对;
操作2结束后,序列为150 140 130,(1,2),(1,3),(2,3)共3对满足条件的(i,j)。
【数据规模和约定】
对于100%的数据,1≤m≤2*103,1≤n≤2*104,1≤hi≤109,ai≠bi,1≤ai,bi≤n。
0
3
【样例说明】
未进行任何操作时,(2,3)满足条件;
操作1结束后,序列为130 140 150,不存在满足i<j且hi>hj的(i,j)对;
操作2结束后,序列为150 140 130,(1,2),(1,3),(2,3)共3对满足条件的(i,j)。
【数据规模和约定】
对于100%的数据,1≤m≤2*103,1≤n≤2*104,1≤hi≤109,ai≠bi,1≤ai,bi≤n。
题解:
一道动态逆序对的题。
对于交换,拆成两个删除,两个插入,注意一开始要把所有数插入。。然后直接上cdq分治。
#include<stdio.h> #include<iostream> #include<algorithm> using namespace std; const int N=20005; const int M=2005; struct node { int a,id; }A[N]; struct Node { int a,b,c,id,No; }p[(M<<2)+N],q[(M<<2)+N]; int n,m,Q,tot,i,k,x,y,h[N],t[N],ans[M]; inline void read(int &v){ char ch,fu=0; for(ch='*'; (ch<'0'||ch>'9')&&ch!='-'; ch=getchar()); if(ch=='-') fu=1, ch=getchar(); for(v=0; ch>='0'&&ch<='9'; ch=getchar()) v=v*10+ch-'0'; if(fu) v=-v; } bool cmp(const node&x,const node&y) { return x.a<y.a; } bool Cmp(const Node&x,const Node&y) { if(x.a!=y.a) return x.a<y.a; return x.b<y.b; } void update(int x,int y) { while(x<=k) t[x]+=y,x+=x&-x; } int solve(int x) { int ans=0; while(x) ans+=t[x],x-=x&-x; return ans; } void add(int x,int y,int z,int Q) { p[++tot].id=tot;p[tot].No=Q; p[tot].a=x;p[tot].b=y;p[tot].c=z; } void solve(int l,int r) { if(l==r) return; int mid=(l+r)>>1,i; for(i=l;i<=r;i++) { if(p[i].id<=mid) update(p[i].b,p[i].c); if(p[i].id>mid) ans[p[i].No]+=p[i].c*(solve(k)-solve(p[i].b)); } for(i=l;i<=r;i++) if(p[i].id<=mid) update(p[i].b,-p[i].c); for(i=r;i>=l;i--) { if(p[i].id<=mid) update(p[i].b,p[i].c); if(p[i].id>mid) ans[p[i].No]+=p[i].c*solve(p[i].b-1); } for(i=l;i<=r;i++) if(p[i].id<=mid) update(p[i].b,-p[i].c); int L=l,R=mid+1; for(i=l;i<=r;i++) if(p[i].id<=mid) q[L++]=p[i];else q[R++]=p[i]; for(i=l;i<=r;i++) p[i]=q[i]; solve(l,mid);solve(mid+1,r); } int main() { read(n); for(i=1;i<=n;i++) read(A[i].a),A[i].id=i; sort(A+1,A+n+1,cmp); k=1;h[A[1].id]=1; for(i=2;i<=n;i++) { if(A[i].a!=A[i-1].a) k++; h[A[i].id]=k; } for(i=1;i<=n;i++) p[++tot].id=tot,p[tot].a=i,p[tot].b=h[i],p[tot].c=1; read(m); for(i=1;i<=m;i++) { read(x),read(y); add(x,h[x],-1,++Q);add(y,h[y],-1,Q); add(x,h[y],1,Q);add(y,h[x],1,Q); swap(h[x],h[y]); } sort(p+1,p+tot+1,Cmp); solve(1,tot); printf("%d\n",ans[0]); for(i=1;i<=m;i++) ans[i]+=ans[i-1],printf("%d\n",ans[i]); return 0; }
一念起,天涯咫尺; 一念灭,咫尺天涯。