2141: 排队
Time Limit: 4 Sec Memory Limit: 259 MBSubmit: 762 Solved: 299
[ Submit][ Status]
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
3
130 150 140
2
2 3
1 3
Sample Output
1
0
3
【样例说明】
未进行任何操作时,(2,3)满足条件;
操作1结束后,序列为130 140 150,不存在满足ihj的(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,不存在满足ihj的(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。
HINT
题意:有M次操作,每次操作,交换位置x,y的数,然后输出逆序对数思路:对于修改操作,(x,y),对于区间内小于a[x]的数逆序对数都少一,大于的都加一,区间内小于a[y]的都加一,大于的都减一
统计小于val的数的个数就用树套树
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=20010;
typedef long long LL;
int N,M,a[maxn];
int X[maxn];
int cnt,tot;
struct Node
{
int ch[2];
int r;//优先级
int v;//值
int s;
int cnt;//自身重复次数
void init(int val){v=val;ch[0]=ch[1]=0;s=cnt=1;r=rand();}
int cmp(int x)const
{
if(x==v)return -1;
return x<v?0:1;
}
}tree[maxn*20];
void maintain(int x)
{
tree[x].s=tree[x].cnt;
tree[x].s+=tree[tree[x].ch[0]].s+tree[tree[x].ch[1]].s;
}
void rotate(int &o,int d)
{
int k=tree[o].ch[d^1];
tree[o].ch[d^1]=tree[k].ch[d];
tree[k].ch[d]=o;
maintain(o);
maintain(k);
o=k;
}
void insert(int &o,int x)
{
if(!o)
{
o=++tot;
tree[o].init(x);
}
else
{
if(x==tree[o].v)tree[o].cnt++;
else
{
int d=(x<tree[o].v?0:1);
insert(tree[o].ch[d],x);
if(tree[tree[o].ch[d]].r>tree[o].r)
rotate(o,d^1);
}
}
maintain(o);
}
void remove(int &o,int x)
{
if(!o)return;
int d=tree[o].cmp(x);
if(d==-1)
{
int u=o;
if(tree[o].cnt>1)tree[o].cnt--;
else if(tree[o].ch[0]&&tree[o].ch[1])
{
int d2=(tree[tree[o].ch[0]].r>tree[tree[o].ch[1]].r?1:0);
rotate(o,d2);
remove(tree[o].ch[d2],x);
}
else
{
if(!tree[o].ch[0])o=tree[o].ch[1];
else o=tree[o].ch[0];
}
}
else remove(tree[o].ch[d],x);
if(o)maintain(o);
}
//返回最大值
int get_max(int o)
{
while(tree[o].ch[0])o=tree[o].ch[0];
return tree[o].v;
}
//返回最小值
int get_min(int o)
{
while(tree[o].ch[1])o=tree[o].ch[1];
return tree[o].v;
}
//返回val的前驱,如果没有的话返回y
//y的初值可赋成0,表示没有前驱
int get_pred(int o,int val,int y)
{
if(!o)return y;
if(tree[o].v<=val)//注意大于等于号
return get_pred(tree[o].ch[1],val,tree[o].v);
else return get_pred(tree[o].ch[0],val,y);
}
//返回val的后继,如果没有的话返回y
//y的初值可赋成0,表示没有后继
int get_succ(int o,int val,int y)
{
if(!o)return y;
if(tree[o].v>=val)return get_succ(tree[o].ch[0],val,tree[o].v);
else return get_succ(tree[o].ch[1],val,y);
}
//返回第k大的元素的值
int get_kth(int o,int k)
{
if(!o)return 0;
if(k<=tree[tree[o].ch[0]].s)return get_kth(tree[o].ch[0],k);
else if(k>tree[tree[o].ch[0]].s+tree[o].cnt)
return get_kth(tree[o].ch[1],k-tree[tree[o].ch[0]].s-tree[o].cnt);
return tree[o].v;
}
//返回val的排名
int get_rank(int o,int val)
{
if(!o)return 0;
int lsize=tree[tree[o].ch[0]].s;
if(val<tree[o].v)
return get_rank(tree[o].ch[0],val);
else if(val>tree[o].v)
return get_rank(tree[o].ch[1],val)+lsize+tree[o].cnt;
return lsize+tree[o].cnt;
}
int tr[maxn];
void update(int x,int val)
{
while(x<=N)
{
insert(tr[x],val);
x+=(x&(-x));
}
}
void erase(int x,int val)
{
while(x<=N)
{
remove(tr[x],val);
x+=(x&(-x));
}
}
int getsum(int x,int val)
{
int sum=0;
while(x)
{
sum+=get_rank(tr[x],val);
x-=(x&(-x));
}
return sum;
}
pair<int,int> cal(int l,int r,int val)
{
int x=getsum(r,val)-getsum(l-1,val);//小于等于val的个数
int y=getsum(r,val-1)-getsum(l-1,val-1);//小于等于val-1的个数
return make_pair(x-y,y);
}
int main()
{
while(scanf("%d",&N)!=EOF)
{
for(int i=1;i<=N;i++)
{
scanf("%d",&a[i]);
X[i]=a[i];
}
sort(X+1,X+1+N);
cnt=unique(X+1,X+N+1)-X-1;
for(int i=1;i<=N;i++)
a[i]=lower_bound(X+1,X+N+1,a[i])-X;
LL ans=0;
pair<int,int> tmp;
tot=0;
memset(tr,0,sizeof(tr));
for(int i=1;i<=N;i++)
{
update(i,a[i]);
tmp=cal(1,i-1,a[i]);
ans+=i-1-tmp.first-tmp.second;
}
printf("%lld\n",ans);
scanf("%d",&M);
while(M--)
{
int x,y;
scanf("%d%d",&x,&y);
if(a[x]==a[y])
{
printf("%lld\n",ans);
continue;
}
if(x>y)swap(x,y);
if(a[x]>a[y])ans--;
else ans++;
if(y-x>1)
{
tmp=cal(x+1,y-1,a[x]);
ans+=y-x-1-tmp.first-tmp.second;
ans-=tmp.second;
tmp=cal(x+1,y-1,a[y]);
ans+=tmp.second;
ans-=y-x-1-tmp.first-tmp.second;
}
erase(x,a[x]);
erase(y,a[y]);
swap(a[x],a[y]);
update(x,a[x]);
update(y,a[y]);
printf("%lld\n",ans);
}
}
return 0;
}
分块写起来更简单一些:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=20010;
const int maxm=200;
int a[maxn],X[maxn];
int N,M;
int block[maxm][maxn];
int size;
int tree[maxn];
void update(int x,int val)
{
while(x<=N)
{
tree[x]+=val;
x+=(x&(-x));
}
}
int getsum(int l,int r)
{
int sum=0;
while(r)
{
sum+=tree[r];
r-=(r&(-r));
}
return sum;
}
void init()
{
size=sqrt(N);
int num=0,j=0;
for(int i=0;i<N;i++)
{
block[num][j]=a[i];
if(++j==size)num++,j=0;
}
for(int i=0;i<num;i++)sort(block[i],block[i]+size);
if(j)sort(block[num],block[num]+j);
}
LL query(int l,int r,int x,int flag)
{
if(l>r)return 0;
int x_pos=l/size;
int y_pos=r/size;
LL ans=0;
if(x_pos==y_pos)
{
for(int i=l;i<=r;i++)
{
if(a[i]<x)ans++;
if(a[i]==x&&flag)ans++;
}
return ans;
}
for(int i=l;i<(x_pos+1)*size;i++)
{
if(a[i]<x)ans++;
if(a[i]==x&&flag)ans++;
}
for(int i=(y_pos)*size;i<=r;i++)
{
if(a[i]<x)ans++;
if(a[i]==x&&flag)ans++;
}
for(int i=x_pos+1;i<y_pos;i++)
{
if(flag)
ans+=upper_bound(block[i],block[i]+size,x)-block[i];
else
ans+=lower_bound(block[i],block[i]+size,x)-block[i];
}
return ans;
}
void change(int x,int val)
{
if(a[x]==val)return ;
int x_pos=x/size;
int pos=0;
while(block[x_pos][pos]<a[x])pos++;
block[x_pos][pos]=val;
if(val<=a[x])
while(pos>0&&block[x_pos][pos]<block[x_pos][pos-1])
swap(block[x_pos][pos],block[x_pos][pos-1]),pos--;
else
while(pos<size-1&&block[x_pos][pos]>block[x_pos][pos+1])
swap(block[x_pos][pos],block[x_pos][pos+1]),pos++;
a[x]=val;
}
int main()
{
while(scanf("%d",&N)!=EOF)
{
int cnt=0;
for(int i=0;i<N;i++)
{
scanf("%d",&a[i]);
X[++cnt]=a[i];
}
sort(X+1,X+cnt+1);
cnt=unique(X+1,X+cnt+1)-X-1;
memset(tree,0,sizeof(tree));
LL ans=0;
for(int i=0;i<N;i++)
{
int pos=lower_bound(X+1,X+cnt+1,a[i])-X;
ans+=i-getsum(1,pos);
update(pos,1);
}
printf("%lld\n",ans);
init();
scanf("%d",&M);
while(M--)
{
int x,y;
scanf("%d%d",&x,&y);
if(x>y)swap(x,y);
x--,y--;
if(a[x]==a[y]||x==y){printf("%d\n",ans);continue;}
if(a[x]<a[y])ans++;
else if(a[x]>a[y])ans--;
ans+=query(x+1,y-1,a[y],0);
ans-=y-x-1-query(x+1,y-1,a[y],1);
ans+=y-x-1-query(x+1,y-1,a[x],1);
ans-=query(x+1,y-1,a[x],0);
int tmp=a[x];
change(x,a[y]);change(y,tmp);
printf("%lld\n",ans);
}
}
return 0;
}