BZOJ 3295 动态逆序对

调了好久。。。。

转化成三维偏序,cdq处理。

好像比较快?

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 300500
using namespace std;
long long n,m,x,a[maxn],pos[maxn],f1[maxn],f2[maxn],t[maxn],ans=0;
struct pnt
{
    long long a,b,c,ans;
}p[maxn];
bool cmp1(pnt x,pnt y) {return x.b<y.b;}
bool cmp2(pnt x,pnt y) {return x.b>y.b;}
bool cmp3(pnt x,pnt y) {return x.a<y.a;}
long long lowbit(long long x) {return (x&(-x));}
void add(long long x,long long val)
{
    for (long long i=x;i<=n;i+=lowbit(i))
        t[i]+=val;
}
long long ask(long long x)
{
    long long ret=0;
    for (long long i=x;i>=1;i-=lowbit(i))
        ret+=t[i];
    return ret;
}
void cdq1(long long left,long long right)
{
    long long mid=left+right>>1;
    sort(p+left,p+mid+1,cmp1);sort(p+mid+1,p+right+1,cmp1);
    long long i=left,j=mid+1;
    while (j<=right)
    {
        while ((i<=mid) && (p[i].b<p[j].b))
        {
            add(p[i].c,1);
            i++;
        }
        p[j].ans+=ask(n)-ask(p[j].c);
        j++;
    }
    for (long long j=left;j<i;j++) add(p[j].c,-1);
}
void cdq2(long long left,long long right)
{
    long long mid=left+right>>1;
    sort(p+left,p+mid+1,cmp2);sort(p+mid+1,p+right+1,cmp2);
    long long i=left,j=mid+1;
    while (j<=right)
    {
        while ((i<=mid) && (p[i].b>p[j].b))
        {
            add(p[i].c,1);
            i++;
        }
        p[j].ans+=ask(p[j].c-1);
        j++;
    }
    for (long long j=left;j<i;j++) add(p[j].c,-1);
}
void cdq(long long left,long long right)
{
    if (left==right) return;
    long long mid=left+right>>1;
    cdq(left,mid);cdq(mid+1,right);
    cdq1(left,right);
    cdq2(left,right);
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for (long long i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        pos[a[i]]=i;
    }
    for (long long i=1;i<=n;i++)
    {
        f1[pos[i]]=(pos[i]-1)-ask(pos[i]-1);
        ans+=f1[pos[i]];
        f2[pos[i]]=ask(n)-ask(pos[i]);
        add(pos[i],1);
    }
    memset(t,0,sizeof(t));
    for (long long i=1;i<=m;i++)
    {
        scanf("%lld",&x);
        p[i].a=i;p[i].b=pos[x];p[i].c=x;
    }
    cdq(1,m);
    sort(p+1,p+m+1,cmp3);
     for (long long i=1;i<=m;i++)
    {
        printf("%lld\n",ans);
        x=p[i].c;
         ans-=(f1[pos[x]]+f2[pos[x]]);
         ans+=(p[i].ans);
    }
    return 0;
}
时间: 2024-10-23 06:01:31

BZOJ 3295 动态逆序对的相关文章

bzoj 3295 动态逆序对 CDQ分支

容易看出ans[i]=ans[i-1]-q[i],q[i]为删去第i个数减少的逆序对. 先用树状数组算出最开始的逆序对,预处理出每个数前边比它大的和后边比它小的,就求出了q[i]的初始值. 设b[i]是第i个删除的数,pos[i]为i在数列里的位置. 对q[i]产生影响的是   1. j<i,pos[b[j]]<pos[b[i]],b[j]>b[i].  2.j<i,pos[b[j]]>pos[b[i]],b[j]<b[i]. 因为是三维的,所以我们套一层cdq. 1

主席树初探 &amp; bzoj 3295: [Cqoi2011] 动态逆序对 题解

[原题] 3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 778  Solved: 263 [Submit][Status] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元

【BZOJ 3295】 [Cqoi2011]动态逆序对

3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1373  Solved: 465 [Submit][Status][Discuss] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数

bzoj3295【CQOI2011】动态逆序对

3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 3122  Solved: 986 [Submit][Status][Discuss] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数

bzoj3295动态逆序对

Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 5362  Solved: 1814[Submit][Status][Discuss] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数

[CQOI2011]动态逆序对

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

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

【BZOJ3295】[Cqoi2011]动态逆序对 cdq分治

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

【Luogu1393】动态逆序对(CDQ分治)

[Luogu1393]动态逆序对(CDQ分治) 题面 题目描述 对于给定的一段正整数序列,我们定义它的逆序对的个数为序列中ai>aj且i < j的有序对(i,j)的个数.你需要计算出一个序列的逆序对组数及其删去其中的某个数的逆序对组数. 输入输出格式 输入格式: 第一行,两个数n,m,表示序列中有n个数,要删去m个数 第二行n个数,表示给定的序列. 第三行m个数,第i个数di表示要删去原序列中的第di个数. 输出格式: 一行m+1个数.第一个数表示给定序列的逆序对组数,第i+1个数表示删去第d