[填坑]一直遗忘的树套树版本动态CDQ

题解: 树状数组维护动态开点线段树 实质上是树状数组对应区间维护一颗动态开点线段树 方便对应区间小于x的个数

#include <bits/stdc++.h>
#define ll long long
const int MAXN=1e5+10;
using namespace std;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-‘0‘,ch=getchar();
    return f*x;
}
typedef struct node{
    int l,r,sum;
}node;
vector<int>vec;
node d[MAXN*85];
int a[MAXN],n,m,cnt,id[MAXN],rt[MAXN];
int get_id(int x){return x&(-x);}
void csh(int x){
    for(int i=x;i<=n;i+=get_id(i))vec.push_back(i);
}
void csh1(int x){
    for(int i=x;i>0;i-=get_id(i))vec.push_back(i);
}
void update(int &x,int l,int r,int t,int vul){
    if(!x)x=++cnt;
    d[x].sum+=vul;
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(t<=mid)update(d[x].l,l,mid,t,vul);
    else update(d[x].r,mid+1,r,t,vul);
}
ll ans=0;
void querty(int x,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr){
        ans+=d[x].sum;return ;
    }
    int mid=(l+r)>>1;
    if(ql<=mid)querty(d[x].l,l,mid,ql,qr);
    if(qr>mid)querty(d[x].r,mid+1,r,ql,qr);
}
int p[MAXN];
void add(int x){
    for(;x<=n;x+=get_id(x))p[x]++;
}
int Sum(int x){
    int ans1=0;
    for(;x>0;x-=get_id(x))ans1+=p[x];
    return ans1;
}
int main(){
    n=read();m=read();cnt=0;
    for(int i=1;i<=n;i++)a[i]=read(),id[a[i]]=i;ll sum=0;
    for(int i=1;i<=n;i++){
        csh(i);
        for(int j=0;j<vec.size();j++)update(rt[vec[j]],1,n,a[i],1);
        vec.clear();
        if(a[i]==n)continue;
        csh1(i);
        for(int j=0;j<vec.size();j++)ans=0,querty(rt[vec[j]],1,n,a[i]+1,n),sum+=ans;
        vec.clear();
    }
    int t;ll num,num1,num2;
    printf("%lld\n",sum);
    for(int i=1;i<min(n,m);i++){
        t=read();
        csh1(id[t]);num=0,num1=0;
        if(t!=n){for(int j=0;j<vec.size();j++)ans=0,querty(rt[vec[j]],1,n,t+1,n),num+=ans;}
        if(t!=1){for(int j=0;j<vec.size();j++)ans=0,querty(rt[vec[j]],1,n,1,t-1),num1+=ans;}
        vec.clear();
        sum-=num+t-1-num1-Sum(t);
        csh(id[t]);
        for(int j=0;j<vec.size();j++)update(rt[vec[j]],1,n,t,-1);
        vec.clear();
        add(t);printf("%lld\n",sum);
    }
    return 0;
}

3295: [Cqoi2011]动态逆序对

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 7107  Solved: 2526
[Submit][Status][Discuss]

Description

对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删

除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数

Input

输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。

以下n行每行包含一个1到n之间的正整数,即初始排列。

以下m行每行一个正整数,依次为每次删除的元素。

N<=100000 M<=50000

Output

输出包含m行,依次为删除每个元素之前,逆序对的个数。

Sample Input

5 4

1

5

3

4

2

5

1

4

2

Sample Output

5

2

2

1

样例解释

(1,5,3,4,2)?(1,3,4,2)?(3,4,2)?(3,2)?(3)。

原文地址:https://www.cnblogs.com/wang9897/p/9490973.html

时间: 2024-08-01 03:24:17

[填坑]一直遗忘的树套树版本动态CDQ的相关文章

[Luogu P3157][CQOI2011]动态逆序对 (树套树)

题面 传送门:[CQOI2011]动态逆序对 Solution 一开始我看到pty巨神写这套题的时候,第一眼还以为是个SB题:这不直接开倒车线段树统计就完成了吗? 然后冷静思考了一分钟,猛然发现单纯的线段树并不能解决这个问题,好像还要在外面再套上一颗树. 这就很shit了.你问我资磁不资磁树套树,我是不资磁的,树套树是暴力数据结构,我能资磁吗? 很不幸,昨天现实狠狠地打了我一脸:时间不够开新坑的,不切题又浑身难受,找了半天题,还是把这道题拉了出来(哈,真香) 不扯淡了,这题还是很显然的. 考虑开

树套树-线段树套平衡树

树套树留坑 线段树套平衡树: 二逼平衡树 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<cmath> #include<map> #include<bitset> #pragma GCC optimize(2) #define rep(i,a,b) for(i

BZOJ_3196_二逼平衡树(树套树:线段树+Treap)

描述 可以处理区间问题的平衡树. 分析 树套树.可以用线段树套Treap.人生第一道树套树的题... op1:如果在整区间,直接在该区间的treap上求解.否则分两个区间求解,然后相加.最后+1. op2:这个不太好直接做,可以二分,每次假定一个值,用这个值去做op1,以此求得一个rank=k+1的数,求rank=k的数等价与求这个数的前驱pre. op3:先删后加. op4&op5:如果在整区间,直接在该区间的treap上求解,否则分量个区间求解,pre取最大值,suc取最小值.注意有些数在有

BZOJ 3110: [Zjoi2013]K大数查询 [树套树]

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6050  Solved: 2007[Submit][Status][Discuss] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a

[BZOJ3110] [Zjoi2013] K大数查询 (树套树)

Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M 接下来M行,每行形如1 a b c或2 a b c Output 输出每个询问的结果 Sample Input 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3 Sample Output 1 2 1 HINT [

bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)

Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的个数. Sample Input 5 4 1 5 3

BZOJ3295 动态逆序对 树套树, 树状数组套线段树(主席树)

Orz黄学长,蒟蒻在黄学长的带领下,通过阅读黄学长的代码!终于会了这道题! 首先我想先说一下这道题的思路(准确来说是黄学长的). 很明显,树状数组应该不用讲吧!关键是内存怎么开,维护一些什么样的数据? 其实我们通过观察,很快可以发现,你维护被删的数比维护所有的数轻松多了(不管是空间上,还是时间上).所以我们就可以从这方面想!(其实我一开始的思路,因为这道题我已经看过很久了,一直想写,毕竟是白书里面的一道例题嘛!一开始,蒟蒻的我是打算这样的用树状数组套权值线段树,并且是维护所有的数,我发现空间不够

HDU HDOJ5412(树套树

题目:要求支持带修改维护区间第k大的值.所谓的动态区间第k大. 思路:题解说的是树状数组套treap,然而没想通树状数组怎么维护...线段树的话就是把所有的值离散化一下,离线建个关于值的线段树,每个节点是一个treap,treap里的值用位置做关键字,然后做区间查询,复杂度是O(nlogn*logn).基本也是经典的树套树做法....然后赛后写了两遍都没过.....今天心血来潮再挑战一下,结果从8点调到晚上1点.其间各种爆内存各种re各种t.....随机数据对拍了好久没拍出问题来....然后一直

bzoj 1901: Zju2112 Dynamic Rankings(树套树)

1901: Zju2112 Dynamic Rankings 经典的带修改求区间第k小值问题 树套树模板,我是用的线段树套splay实现的,而且用的数组模拟的,所以可能空间略大,bzoj过了,zoj过不了. 思路很简单,用线段树维护区间,用splay维护区间内的权值,然后询问的时候,二分答案key,然后在区间内找小于key的数有多少个. 贴上模板: #include<stdio.h> #include<string.h> #include<algorithm> #def

POJ 1195 2维线段树(树套树实现) 树状数组

1: #include <stdio.h> 2: #include <string.h> 3: #include <stdlib.h> 4: #include <algorithm> 5: #include <iostream> 6: using namespace std; 7:   8: #define LL(a) a<<1 9: #define RR(a) a<<1|1 10: const int MaxL = 10