UVA 11990(BIT套treap

题目:给出一个1到n的全排列,m个询问,每次删除一个数,输出此时总的逆序对数.

思路:树状数组每个节点都是treap,通过bit套treap来查询每个点前面有多少个比该点小的数...

思路还是比较简单的,但是写了挺长时间,现在一个很严重的缺点就是代码量一大就没有定力,然后直接gg.....以后要多写代码题尽力克服这个问题...

/*
* @author:  Cwind
*/
///#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
#include <functional>
#include <set>
#include <cmath>
using namespace std;
#define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
#define pb push_back
#define PB pop_back
#define bk back()
#define fs first
#define se second
#define sq(x) (x)*(x)
#define eps (3e-7)
#define IINF (1<<29)
#define LINF (1ll<<59)
#define INF (1000000000)
#define FINF (1e3)
#define clr(x) memset((x),0,sizeof (x));
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<int,int> P;

const int MAXTREAPNODE=2e5*40;
struct treapNode{
    treapNode *ch[2];
    int right,val;
    int sz;
    treapNode():sz(0){}
    int cmp(int x) const {
        if(x==val) return -1;
        return x>val;
    }
    void maintain(){
        sz=ch[0]->sz+ch[1]->sz+1;
    }
}pool[MAXTREAPNODE];
int ph;
treapNode *null=new treapNode();
treapNode *newtreapNode(int v){
    treapNode *n=&pool[ph++];
    n->val=v;
    n->right=rand();
    n->ch[0]=n->ch[1]=null;
    n->sz=0;
    return n;
}
struct Treap{
    treapNode *root;
    void init(){
        root=null;
    }
    void rotate(treapNode *&o,int d){
        treapNode *k=o->ch[d^1];
        o->ch[d^1]=k->ch[d];
        k->ch[d]=o;
        o->maintain();
        k->maintain();
        o=k;
    }
    void insert(treapNode *&o,int x){
        if(o==null) o=newtreapNode(x);
        else{
            int d=o->val<x;
            insert(o->ch[d],x);
            if(o->ch[d]->right>o->right) rotate(o,d^1);
        }
        o->maintain();
    }
    void insert(int x){insert(root,x);}
    void remove(treapNode *&o,int x){
        int d=o->cmp(x);
        if(d==-1){
            if(o->ch[0]==null) o=o->ch[1];
            else if(o->ch[1]==null) o=o->ch[0];
            else{
                int d2=o->ch[0]->right>o->ch[1]->right;
                rotate(o,d2);
                remove(o->ch[d2],x);
            }
        }else remove(o->ch[d],x);
        if(o!=null) o->maintain();
    }
    void remove(int x){remove(root,x);}
    int calless(treapNode *n,int x){
        if(n==null) return 0;
        int ans=0;
        if(n->val<x){
            ans+=n->ch[0]->sz+1;
            ans+=calless(n->ch[1],x);
        }else{
            ans+=calless(n->ch[0],x);
        }
        return ans;
    }
    int cal(int x){return calless(root,x);}
};
const int maxn=2e5+3000;
struct BIT2{
    int B[maxn];
    void init(){clr(B);}
    int sum(int p){
        int ans=0;
        while(p>0){
            ans+=B[p];
            p-=p&-p;
        }
        return ans;
    }
    void add(int p,int x){
        while(p<maxn){
            B[p]+=x;
            p+=p&-p;
        }
    }
}A,cnt;
struct BIT{
    Treap B[maxn];
    void init(){
        for(int i=0;i<maxn;i++)
            B[i].init();
    }
    void insert(int p,int a){
        while(p<maxn){
            B[p].insert(a);
            p+=p&-p;
        }
    }
    void delet(int p,int a){
        while(p<maxn){
            B[p].remove(a);
            p+=p&-p;
        }
    }
    int getless(int p,int x){
        int ans=0;
        while(p>0){
            ans+=B[p].cal(x);
            p-=p&-p;
        }
        return ans;
    }
}B;
int n,m;
int sq[maxn];
int pos[maxn];
ll ans;
void init(){
    ph=0;
    ans=0;
    A.init();B.init();cnt.init();
}
int main(){
    freopen("/home/slyfc/CppFiles/in","r",stdin);
    //freopen("defense.in","r",stdin);
    //freopen("defense.out","w",stdout);
    while(cin>>n>>m){
        init();
        for(int i=1;i<=n;i++){
            scanf("%d",&sq[i]);
            pos[sq[i]]=i;
            ans+=i-A.sum(sq[i])-1;
            A.add(sq[i],1);
            cnt.add(i,1);
            B.insert(i,sq[i]);
        }
        for(int i=0;i<m;i++){
            cout<<ans<<endl;
            int x;
            scanf("%d",&x);
            int p=pos[x];
            int tolless=A.sum(x)-1;
            int foreless=B.getless(p,x);
            int foretol=cnt.sum(p)-1;
            ans-=tolless-foreless;
            ans-=foretol-foreless;
            A.add(x,-1);cnt.add(p,-1);
            B.delet(p,x);
        }
    }
    return 0;
}

时间: 2024-08-02 10:51:10

UVA 11990(BIT套treap的相关文章

UVA 11990 ``Dynamic&#39;&#39; Inversion

26天以前做过的一道题,之前的做法是分治预处理,树套树在线修改,复杂度为O(nlogn+m*logn*logn),代码量较大. 本来想学习一下cdq分治的,看到论文上的凸包.斜率就暂时放一边了,只知道和一般的分治的不同是左子问题可以用来解决右边的子问题. 今天下午YY了一个离线的分治做法. 对于每一个数字,构成逆序对除了val大小还和被删除的时间del有关,这实际上是一个三维偏序的问题. 一个元素是一个三元组e(pos,val,del),e1和e2对答案有贡献当且仅当e1.pos < e1.po

Bestcoder7(1004)hdu4988(经典问题:树状数组套treap求解动态逆序对)

Little Pony and Boast Busters Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 83    Accepted Submission(s): 32 Problem Description "I hereby challenge you, Ponyvillians: anything you can do

BZOJ 3196 二逼平衡树 树套树(线段树套Treap)

题目大意: 写一种数据结构,他可以: 1.查询k在区间内的排名. 2.查询区间内排名为k的值 3.修改某一个值. 4.求k在区间内的前驱. 5.求k在区间内的后继. 思路:本来以为有什么只有神犇才知道的神一般的数据结构来维护它,问了别人之后,发现只是树套树.据说怎么套都行.我见识鄙陋,就只能线段树套Treap了. 这也是第一次写树套树,还1A了,有点开心. 写树套树,一定要确定自己对这两个树及其熟练,加上少量精细的思考,就可以完成树套树.(我只是弱渣,求神犇别D) 具体实现:第一层是线段树,第二

UVA 11990 `Dynamic&#39;&#39; Inversion CDQ分治, 归并排序, 树状数组, 尺取法, 三偏序统计 难度: 2

题目 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3141 题意 一个1到n的排列,每次随机删除一个,问删除前的逆序数 思路 综合考虑,对每个数点,令value为值,pos为位置,time为出现时间(总时间-消失时间),明显是统计value1 > value2, pos1 < pos2, time1 < time2的个

zoj 2112 Dynamic Rankings 动态第k大 线段树套Treap

Dynamic Rankings Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112 Description The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query l

【bzoj3196】 Tyvj 1730 二逼平衡树 线段树套Treap

题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) 输入 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行有n个数,表示有序序列下面有m行,opt表示操作标号若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名若opt=2 则为操

BZOJ 3295 CQOI 2011 动态逆序对 线段树套Treap

题目大意:给出一个数列,每次从这个序列中删掉一个数字,问每次删之前逆序对的数量是多少. 思路:这个题用CDQ分治是飞快的,然而我不知道怎么写..于是就朴素的写了树套树.然后就朴素的被卡常了 内层用一个线段树.这个线段树不修改,一开始就要建好,然后线段树的每一个节点维护一个平衡树,存的是线段树存的区间中所有的值. 一开始先算一下逆序对数,然后每次删点的时候,先查询在这个点之前有多少大于他的,后面有多少小于他的,总的逆序对中将这些减掉.这个过程通过树套树不难实现. CODE(交了这个代码T掉的,请选

bzoj 3196 &amp;&amp; luogu 3380 JoyOI 1730 二逼平衡树 (线段树套Treap)

链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3196 题面; 3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 6372  Solved: 2406[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为

[bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)

Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作 第二行有n个数,表示有序序列 下面有m行,opt表示操作标号 若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间