bzoj3295

cdq分治

我们把每个数都视作插入和询问,那么每个询问就是当前的贡献。。。

事实上这道题可以看做一个三维偏序:(t,v,pos) 插入时间,值,插入位置

两个数当且仅当形成逆序对时是x,y,x的插入时间比y早,x的值比y小,x在y的后面,x的值比y大,x在y的前面。

那么就可以cdq分治了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 400010
#define lowbit(i) i&-i
struct query
{
    int v,id,pos,type;
}q[N];
int n,tot,m;
ll a[N],b[N],tree[N],ans[N],pos[N];
bool flag[N];
vector<query> c;
inline void update(int pos,int delta) {for(int i=pos;i<=n;i+=lowbit(i)) tree[i]+=delta; }
inline ll sum(int pos) {ll ret=0; for(int i=pos;i;i-=lowbit(i)) ret+=tree[i]; return ret;}
inline bool cp1(query x,query y) {if(x.pos!=y.pos) return x.pos<y.pos; return x.type<y.type;}
inline bool cp2(query x,query y) {if(x.pos!=y.pos) return x.pos>y.pos; return x.type<y.type;}
void cdq(int l,int r)
{
    if(l>=r) return;
    int mid=(l+r)>>1;
    cdq(l,mid); cdq(mid+1,r);
    c.clear();
    for(int i=l;i<=mid;++i) if(q[i].type==1) c.push_back(q[i]);
    for(int i=mid+1;i<=r;++i) if(q[i].type==2) c.push_back(q[i]);
    sort(c.begin(),c.end(),cp1);
    for(int i=0;i<c.size();++i)
    {
        if(c[i].type==1) update(c[i].v,1);
        if(c[i].type==2) ans[c[i].id]+=sum(n)-sum(c[i].v);
    }
    for(int i=0;i<c.size();++i) if(c[i].type==1) update(c[i].v,-1);
    sort(c.begin(),c.end(),cp2);
    for(int i=0;i<c.size();++i)
    {
        if(c[i].type==1) update(c[i].v,1);
        if(c[i].type==2) ans[c[i].id]+=sum(c[i].v-1);
    }
    for(int i=0;i<c.size();++i) if(c[i].type==1) update(c[i].v,-1);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&a[i]);
        pos[a[i]]=i;
    }
    for(int i=1;i<=m;++i)
    {
        scanf("%d",&b[i]);
        flag[b[i]]=1;
    }
    int t=0;
    for(int i=1;i<=n;++i) if(!flag[a[i]])
    {
         q[++tot].v=a[i];
         q[tot].type=1;
         q[tot].pos=pos[a[i]];
         q[++tot].v=a[i];
         q[tot].type=2;
         q[tot].pos=pos[a[i]];
         q[tot].id=++t;
    }
    for(int i=m;i;--i)
    {
        q[++tot].v=b[i];
        q[tot].pos=pos[b[i]];
        q[tot].type=1;
        q[++tot].v=b[i];
        q[tot].pos=pos[b[i]];
        q[tot].type=2;
        q[tot].id=++t;
    }
    cdq(1,tot);
    for(int i=1;i<=n;++i) ans[i]+=ans[i-1];
    for(int i=n;i>=n-m+1;--i) printf("%lld\n",ans[i]);
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

时间: 2024-10-07 04:12:06

bzoj3295的相关文章

【bzoj3295】 Cqoi2011—动态逆序对

http://www.lydsy.com/JudgeOnline/problem.php?id=3295 (题目链接) 题意 给出某种排列,按照某种顺序依次删除m个数,在每次删除一个数前统计序列中逆序对对个数. Solution 作为一个CDQ分治的初学者,我毫不犹豫的%了LCF的题解. 这里介绍下三维偏序的求法:一维排序,二维归并,三维树状数组. 排序维护x维之后,递归处理: 1.在处理区间[L,R]的时候,先二分区间[L, (L+R)/ 2],递归求这个左区间(二分的原因是我在维护y维的时候

【CQOI2011】动态逆序对 BZOJ3295

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】[Cqoi2011]动态逆序对 cdq分治

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

【bzoj3295】动态逆序对

我怎么控制不住自己又写了个数据结构啊--真是的-- 其实我是想练CDQ分治的--结果忍不住又写了个主席树. 首先看看不动态的逆序对咋做?树状数组嘛. 那么删除咋搞?就是考虑贡献,把它前面比他大的,后面比他小的减去-- 诶?带修改主席树?我--我好像才写过--? 1 #include<bits/stdc++.h> 2 #define inf 0x7fffffff 3 #define N 100005 4 #define M 5000005 5 using namespace std; 6 typ

[BZOJ3295][Cqoi2011]动态逆序对

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

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

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

【BZOJ3295】【CQOI2011】动态逆序对

cdq分治经典例题,然而智商掉线傻逼错误坑了两天 原题: 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. N<=100000 M<=50000 此题修改和询问绑定完全离线,可以直接倒序变成插入,然后就是三维数星星辣(? ?????)? x为下标,y为值,z为时间轴,x排序,z_cdq分治,y树状数组 不用搞两次cdq分治,每次按x递增查找比y大的

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(线段树套平衡树(treap))

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