BZOJ 2141排队(树状数组套Treap)

2141: 排队

Time Limit: 4 Sec   Memory Limit: 259 MB
Submit: 798   Solved: 323
[ Submit][ Status][ Discuss]

Description

排排坐,吃果果,生果甜嗦嗦,大家笑呵呵。你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和。红星幼儿园的小朋友们排起了长长地队伍,准备吃果果。不过因为小朋友们的身高有所区别,排成的队伍高低错乱,极不美观。设第i个小朋友的身高为hi,我们定义一个序列的杂乱程度为:满足hi>hj且i<j的(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

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*10^3,1≤n≤2*10^4,1≤hi≤10^9,ai≠bi,1≤ai,bi≤n。
代码写的不是很美,不过需要注意的是找到的节点必须是严格大于或者小于

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
#define lowbit(x) (x&-x)
#define N 20100
int n,m,ans,num[N];
struct Node{
    Node *ch[2];
    int rank,value,siz;
    Node() {ch[0]=ch[1]=NULL;}
    Node(int v,int r) {
        ch[0] = ch[1] = NULL;
        value = v; rank = r; siz = 1;
    }
    void push_up() {
        siz = 1;
        if(ch[0]!=NULL) siz += ch[0]->siz;
        if(ch[1]!=NULL) siz += ch[1]->siz;
    }
}*root[N];
//单旋转操作
void rotate(Node *(&node),int d) {
    Node *tem = node->ch[d^1];
    node->ch[d^1] = tem->ch[d];
    node->push_up();
    tem->ch[d] = node;
    tem->push_up();
    node = tem;
}
//插入一个新节点
void insert(Node *(&node),int v) {
    if(node==NULL){ node = new Node(v,rand()); return; }
    int d = (node->value <= v);
    insert(node->ch[d],v);
    node->push_up();
    if(node->ch[d]->rank > node->rank)
        rotate(node,d^1);
}
//查找小于v的数量tag==0不严格
int quary(Node *(&node),int v,int tag) {
    if(node == NULL) return 0;
    int size = (node->ch[0]==NULL?0:node->ch[0]->siz);
    if(tag==0){
        if(node->value <= v) return size+1+quary(node->ch[1],v,tag);
        else                 return quary(node->ch[0],v,tag);
    }
    else{
        if(node->value < v) return size+1+quary(node->ch[1],v,tag);
        else                return quary(node->ch[0],v,tag);
    }
}
//移除node节点
void remove(Node *(&node)){
    if(node->ch[0]==NULL){node = node->ch[1];return;}
    if(node->ch[1]==NULL){node = node->ch[0];return;}
    int rank1 = node->ch[0]->rank;
    int rank2 = node->ch[1]->rank;
    int d = (rank1>rank2)?1:0;
    rotate(node,d);
    remove(node->ch[d]);
    node -> push_up();
}
//移除节点权值为v的节点
void modify(Node *(&node),int v){
    if(node==NULL) return;
    if(node->value == v){ remove(node); return; }
    int d = (node->value < v);
    modify(node->ch[d],v);
    node->push_up();
}
void add(int id,int v){
    for(int i = id;i<=n;i+=lowbit(i))
        insert(root[i],v);
}
//得到id位置之前比y值小的数个数
int getSum(int id,int y,int tag){
    int sum = 0;
    for(int i = id;i>=1;i-=lowbit(i))
        sum += quary(root[i],y,tag);
    return sum;
}
void change(int id,int v1,int v2){
    for(int i = id;i<=n;i+=lowbit(i)){
        modify(root[i],v1);
        insert(root[i],v2);
    }
}
void delet(Node *(&node)){
    if(node == NULL) return;
    delet(node->ch[0]);
    delet(node->ch[1]);
    delete node; node = NULL;
}
void init(){
    ans = 0;
    for(int i = 0;i<=n;i++){
        delet(root[i]);
        root[i] = NULL;
    }
}
int main(){
    int x,y;
    //freopen("Test.txt","r",stdin);
    while(~scanf("%d",&n)){
        init();
        for(int i = 1;i<=n;i++){
            scanf("%d",&num[i]);
            add(i,num[i]);
        }
        for(int i = 1;i<=n;i++){
            ans += (i-1 - getSum(i-1,num[i],0));
        }
        printf("%d\n",ans);
        scanf("%d",&m);
        for(int i = 1;i<=m;i++){
            scanf("%d%d",&x,&y);
            if(x > y) swap(x,y);
            int dox = getSum(y-1,num[x],1) - getSum(x,num[x],1);
            int upx = y-1-x-getSum(y-1,num[x],0) + getSum(x,num[x],0);
            int doy = getSum(y-1,num[y],1) - getSum(x,num[y],1);
            int upy = y-1-x-getSum(y-1,num[y],0) + getSum(x,num[y],0);
            ans -= (dox+upy);
            ans += (doy+upx);
            if(num[x]>num[y]) ans -= 1;
            if(num[x]<num[y]) ans += 1;
            printf("%d\n",ans);
            change(x,num[x],num[y]);
            change(y,num[y],num[x]);
            swap(num[x],num[y]);
        }
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值