[填坑]一直遗忘的树套树版本动态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)。

posted @ 2018-08-17 00:31  wang9897  阅读(132)  评论(0编辑  收藏  举报