题解-P3157 [CQOI2011]动态逆序对

Posted wanghaoyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解-P3157 [CQOI2011]动态逆序对相关的知识,希望对你有一定的参考价值。

树状数组套线段树,用动态开点线段树。此类就这一题放在这吧。

程序写的太丑了,不要介意

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long i64;
const int N=1e5+5;
const int S=1e7+7;

int a[N],p[N];
int q[N];
bool b[N];

int r[N];
int cnt,x[S],c[S][2];

i64 ans[N];

void add(int &v,int xx,int l,int r)
    if(!v)
        v=++cnt;
    ++x[v];
    if(l==r)
        return;
    int mid=(l+r)>>1;
    if(xx<=mid)
        add(c[v][0],xx,l,mid);
    else
        add(c[v][1],xx,mid+1,r);


int ct(int &v,int xx,int yy,int l,int r)
    if(!v)
        return 0;
    if(xx<=l&&r<=yy)
        return x[v];
    int mid=(l+r)>>1,s=0;
    if(xx<=mid)
        s+=ct(c[v][0],xx,yy,l,mid);
    if(mid<yy)
        s+=ct(c[v][1],xx,yy,mid+1,r);
    return s;


int n;

void ins(int p,int a)
    int i;
    for(i=p;i<=n;i+=-i&i)
        add(r[i],a,1,n);


int clc(int p,int a)
    int i,s=0;
    for(i=p;i;i-=-i&i)
        s+=ct(r[i],a+1,n,1,n);
    for(i=n;i;i-=-i&i)
        s+=ct(r[i],1,a-1,1,n);
    for(i=p;i;i-=-i&i)
        s-=ct(r[i],1,a-1,1,n);
    return s;


int main()

    int m,i;
    i64 s=0;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
        p[a[i]]=i;
    
    for(i=1;i<=m;i++)
        scanf("%d",&q[i]);
        b[p[q[i]]]=1;
    
    for(i=1;i<=n;i++)
        if(!b[i])
            s+=clc(i,a[i]);
            ins(i,a[i]);
        
    for(i=m;i;i--)
        s+=clc(p[q[i]],q[i]);
        ins(p[q[i]],q[i]);
        ans[i]=s;
    
    for(i=1;i<=m;i++)
        printf("%lld\n",ans[i]);
    return 0;

用cdq分治更好。

 

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long i64;
const int N=1e5+5;

i64 ans[N];
struct inf
    int p,t;
    i64 *q;
x[N],y[N];
int n;
int bt[N],mt[N];
int a[N],q[N];

void add(int t)
    for(;t<=n;t+=t&-t)
        ++bt[t];


void dec(int t)
    for(;t<=n;t+=t&-t)
        --bt[t];


int ask(int t)
    int s=0;
    for(;t;t-=t&-t)
        s+=bt[t];
    return s;


void _add(int t)
    for(;t<=n;t+=t&-t)
        ++mt[t];


void _dec(int t)
    for(;t<=n;t+=t&-t)
        --mt[t];


int _ask(int t)
    int s=0;
    for(;t;t-=t&-t)
        s+=mt[t];
    return s;


void cdqdc(int l,int r)
    if(l==r)
        return;
    int mid=(l+r)>>1;
    cdqdc(l,mid);
    cdqdc(mid+1,r);
    int i,j,p;
    for(i=l;i<=mid;i++)
        _add(x[i].t);
    for(i=l,j=mid+1,p=l;i<=mid||j<=r;p++)
        if(j>r||i<=mid&&x[i].p<x[j].p)
            *x[i].q+=ask(x[i].t);
            _dec(x[i].t);
            y[p]=x[i++];
        
        else
            add(x[j].t);
            *x[j].q+=_ask(x[j].t);
            y[p]=x[j++];
        
    for(j=mid+1;j<=r;j++)
        dec(x[j].t);
    for(p=l;p<=r;p++)
        x[p]=y[p];


int main()

    int m,i;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
        x[a[i]].p=i;
        x[a[i]].q=ans+m+1;
    
    for(i=1;i<=m;i++)
        scanf("%d",&q[i]);
        x[q[i]].t=n-i+1;
        x[q[i]].q=ans+i;
    
    int s=0;
    for(i=1;i<=n;i++)
        if(!x[i].t)
            x[i].t=++s;
    cdqdc(1,n);
    for(i=m;i;i--)
        ans[i]+=ans[i+1];
    for(i=1;i<=m;i++)
        printf("%lld\n",ans[i]);
    return 0;

 

以上是关于题解-P3157 [CQOI2011]动态逆序对的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P3157 [CQOI2011]动态逆序对 | CDQ分治

P3157 [CQOI2011]动态逆序对

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

P3157 [CQOI2011]动态逆序对(CDQ分治)

LUOGU P3157 [CQOI2011]动态逆序对(CDQ 分治)

luogu P3157 [CQOI2011]动态逆序对(CDQ分治)