传送门:点击打开链接
Go to movies Ⅱ
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 84 Accepted Submission(s): 37
Problem Description
LeLe is tired of playing blocks , so he decides to go to the movies with his friends again.
When the conductor sees LeLe again , he thinks LeLe is a smart boy.If LeLe can accomplish the task given by her ,LeLe and his friends can enjoy a free film!
The task is :
All kids line up( n
kids in total) and LeLe should find out how many pairs of kids stand in wrong position (the tall kids stands in front of the short kids.
i<j
&&
H
i
>H
j![]()
).As time goes by,some friends will join the line and some kids is so impatience that leave the line.LeLe should work out how many pairs of kids stand in wrong position when a kid leaves or joins.
However LeLe knows the relative height of all kids.The shortest is 1,and the tallest is n
.
When the conductor sees LeLe again , he thinks LeLe is a smart boy.If LeLe can accomplish the task given by her ,LeLe and his friends can enjoy a free film!
The task is :
All kids line up( n
However LeLe knows the relative height of all kids.The shortest is 1,and the tallest is n
Input
There are multiple test cases, about
10
cases.
The first line of input contains two integers n,m(1≤n,m≤20000)
.
The second line contains n
integers
H
1
,H
2
,...,H
n
(1≤H
i
≤n)
,indicate the height of each kids in the initial queue from left to right.
For the next m
lines ,each line means a kid leave or join.
0
x
y
means a kid of
y
height stands behind the
xth
kid,
x=0
means stand at the front of the queue.
(1≤y≤n)
1
x
indicate the
xth
(from left to right) kid leave.
The first line of input contains two integers n,m(1≤n,m≤20000)
The second line contains n
For the next m
0
1
Output
There are multiple test cases, about
10
cases.
For each operation puts how many pairs of kids stand in wrong position.
For each operation puts how many pairs of kids stand in wrong position.
Sample Input
5 5 5 4 3 2 1 0 0 2 0 1 3 1 3 1 3 1 3
Sample Output
11 13 9 6 4HintAfter operator 1,the height of every kid is 2 5 4 3 2 1. The total pairs of wrong position is 11. After operator 2,the height of every kid is 2 3 5 4 3 2 1. The total pairs of wrong position is 13. After operator 3,the height of every kid is 2 3 4 3 2 1. The total pairs of wrong position is 9. After operator 4,the height of every kid is 2 3 3 2 1. The total pairs of wrong position is 6. After operator 5,the height of every kid is 2 3 2 1. The total pairs of wrong position is 4. All operators are legal.
Source
题意:求序列的动态逆序对数,0代表在某位置之后插入一个数,1代表删除某位置的数。每次操作完成之后输出当前序列的逆序数。
思路:数据量不大,只有2W。由于有插入的删除操作,考虑使用块状链表。每个块中建立一个安值建树树状数组,方便统计大于某数或小于某数的个数。当插入的时候,在插入的块之前的块,直接用树状数组求出比这个数大的数的个数,在插入的块之后的块,直接用数组数组求出比这个数小的数的个数,在当前块中,暴力求出比这个数小或大的数的个数。一次操作的时间复杂度为sqrt(n)+sqrt(n)。删除和插入类似。
代码:
#include<cstdio>
#include<cstring>
using namespace std;
const int m=150;
inline int lowbit(int x)
{
return x&-x;
}
void add(int c[],int pos,int x)
{
while(pos<=20000)
{
c[pos]+=x;
pos+=lowbit(pos);
}
}
int sum(int c[],int l,int r)
{
int sum1=0,sum2=0;
l--;
while(l>0)
{
sum1+=c[l];
l-=lowbit(l);
}
while(r>0)
{
sum2+=c[r];
r-=lowbit(r);
}
return sum2-sum1;
}
struct data
{
int s,a[2*m+5];
data *next;
int c[20005];
data()
{
memset(c,0,sizeof(c));
next=NULL;
}
};
data *root;
void insert(int x,int pos)
{
if(root==NULL)
{
root=new data;
root->s=1;
root->a[1]=x;
add(root->c,x,1);
return ;
}
data *k=root;
while(pos>k->s && k->next!=NULL)
{
pos-=k->s;
k=k->next;
}
memmove(k->a+pos+1,k->a+pos,sizeof(int)*(k->s-pos+1));
k->s++;
k->a[pos]=x;
add(k->c,x,1);
if(k->s==2*m)
{
data *t=new data;
t->next=k->next;
k->next=t;
memcpy(t->a+1,k->a+m+1,sizeof(int)*m);
for(int i=1;i<=m;i++)
{
add(k->c,t->a[i],-1);
add(t->c,t->a[i],1);
}
t->s=k->s=m;
}
}
void del(int pos)
{
data *k=root;
while(pos>k->s && k->next!=NULL)
{
pos-=k->s;
k=k->next;
}
add(k->c,k->a[pos],-1);
memmove(k->a+pos,k->a+pos+1,sizeof(int)*(k->s-pos));
k->s--;
}
int find(int pos)
{
data *k=root;
while(pos>k->s && k->next!=NULL)
{
pos-=k->s;
k=k->next;
}
return k->a[pos];
}
int work(int pos)
{
int res=0;
data *k=root;
int x=find(pos);
while(pos>k->s && k->next!=NULL)
{
pos-=k->s;
res+=sum(k->c,x+1,20000);
k=k->next;
}
for(int i=1;i<pos;i++) if(k->a[i]>x) res++;
for(int i=pos+1;i<=k->s;i++) if(k->a[i]<x) res++;
while(k->next!=NULL)
{
k=k->next;
res+=sum(k->c,1,x-1);
}
return res;
}
void destroy(data *k)
{
if(k->next!=NULL) destroy(k->next);
delete k;
}
int main()
{
int n,p;
while(~scanf("%d %d",&n,&p))
{
root=NULL;
int ans=0;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
insert(x,i);
ans+=work(i);
}
while(p--)
{
int c;
scanf("%d",&c);
if(c==0)
{
int x,y;
scanf("%d %d",&x,&y);
x++;
insert(y,x);
ans+=work(x);
}
else
{
int x;
scanf("%d",&x);
// x++;
ans-=work(x);
del(x);
}
printf("%d\n",ans);
}
destroy(root);
}
return 0;
}