BZOJ 2141: 排队 CDQ分治+bit

2141: 排队

Description

排排坐,吃果果,生果甜嗦嗦,大家笑呵呵。你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和。红星幼儿园的小朋友们排起了长长地队伍,准备吃果果。不过因为小朋友们的身高有所区别,排成的队伍高低错乱,极不美观。设第i个小朋友的身高为hi,我们定义一个序列的杂乱程度为:满足ihj的(i,j)数量。幼儿园阿姨每次会选出两个小朋友,交换他们的位置,请你帮忙计算出每次交换后,序列的杂乱程度。为方便幼儿园阿姨统计,在未进行任何交换操作时,你也应该输出该序列的杂乱程度。

Input

第一行为一个正整数n,表示小朋友的数量;第二行包含n个由空格分隔的正整数h1,h2,…,hn,依次表示初始队列中小朋友的身高;第三行为一个正整数m,表示交换操作的次数;以下m行每行包含两个正整数ai和bi¬,表示交换位置ai与位置bi的小朋友。

Output

输出文件共m行,第i行一个正整数表示交换操作i结束后,序列的杂乱程度。

Sample Input

【样例输入】
3
130 150 140
2
2 3
1 3

Sample Output

1
0
3
【样例说明】
未进行任何操作时,(2,3)满足条件;
操作1结束后,序列为130 140 150,不存在满足i<j且hi>hj的(i,j)对;
操作2结束后,序列为150 140 130,(1,2),(1,3),(2,3)共3对满足条件的(i,j)。
【数据规模和约定】
对于100%的数据,1≤m≤2*103,1≤n≤2*104,1≤hi≤109,ai≠bi,1≤ai,bi≤n。

HINT

题解:

  分块+bit可做

  用来练习cdq分治,其实和3295动态逆序对是一样的

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double pi = acos(-1.0);
const int N = 5e5+10, M = 1e3+20,inf = 2e9,mod = 1e9+7;

int C[N],n,m,a[N],b[N];
void update(int x,int c) {
    for(int i = x; i <= n; i += i&(-i)) {
        C[i] += c;
    }
}
int sum(int x) {
    int ret = 0;
    for(int i = x; i; i -= i&(-i)) {
        ret += C[i];
    }
    return ret;
}
struct ss{
    int l,r,t,qid,type;
    ss(){}
    ss(int a,int b,int c,int d,int e):l(a),r(b),t(c),qid(d),type(e){}
    bool operator < (const ss &x) const {
        if(l == x.l) return t < x.t;
        else return l < x.l;
    }
}q[N],t[N];
int ans[N];
void cdq(int ll,int rr) {
    if(ll == rr) return ;
    for(int i = ll; i <= rr; ++i) {
        if(q[i].t <= mid) update(q[i].r,q[i].type);
        else ans[q[i].qid] += q[i].type*(sum(n) - sum(q[i].r));
    }
    for(int i = ll; i <= rr; ++i)
        if(q[i].t <= mid) update(q[i].r,-q[i].type);
    for(int i = rr; i >= ll; --i) {
        if(q[i].t <= mid) update(q[i].r,q[i].type);
        else {
            ans[q[i].qid] += q[i].type*(sum(q[i].r-1));
        }
    }
     for(int i = ll; i <= rr; ++i)
        if(q[i].t <= mid) update(q[i].r,-q[i].type);
    int L1 = ll, R1 = mid+1;
    for(int i = ll; i <= rr; ++i)
        if(q[i].t <= mid) t[L1++] = q[i];
     else t[R1++] = q[i];
     for(int i = ll; i <= rr; ++i) q[i] = t[i];
     cdq(ll,mid);cdq(mid+1,rr);
}
int main() {
    scanf("%d",&n);
    for(int i = 1; i <= n; ++i)
        scanf("%d",&a[i]),b[i] = a[i];
    sort(b+1,b+n+1);
    int SC = unique(b+1,b+n+1) - b - 1;
    int cnt = 0;
    for(int i = 1; i <= n; ++i) {
        a[i] = lower_bound(b+1,b+SC+1,a[i]) - b;
        q[++cnt] = ss(i,a[i],cnt,0,1);
    }
    scanf("%d",&m);
    for(int i = 1; i <= m; ++i) {
        int x,y;
        scanf("%d%d",&x,&y);
        q[++cnt] = ss(x,a[y],cnt,i,1);
        q[++cnt] = ss(x,a[x],cnt,i,-1);
        q[++cnt] = ss(y,a[x],cnt,i,1);
        q[++cnt] = ss(y,a[y],cnt,i,-1);
        swap(a[x],a[y]);
    }
    sort(q+1,q+cnt+1);
    cdq(1,cnt);
    printf("%d\n",ans[0]);
    for(int i = 1; i <= m; ++i) ans[i] += ans[i-1];
    for(int i = 1; i <= m; ++i) cout<<ans[i]<<endl;
    return 0;
}
时间: 2024-10-08 09:01:04

BZOJ 2141: 排队 CDQ分治+bit的相关文章

BZOJ 3262: 陌上花开 [CDQ分治 三维偏序]

Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb.显然,两朵花可能有同样的属性.需要统计出评出每个等级的花的数量. Input 第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分别表示花的数量和最大属性值. 以下N行,每

BZOJ 1492 货币兑换 cdq分治或平衡树维护凸包

题意:链接 方法:cdq分治或平衡树维护凸包 解析: 这道题我拒绝写平衡树的题解,我仅仅想说splay不要写挂,insert边界条件不要忘.del点的时候不要脑抽d错.有想写平衡树的去看140142或者留言我. 首先这道题能推出个表达式 f[i]代表第i天最大收益. xx[i]表示将第i天的钱都买A的数量 yy[i]表示将第i天的钱都买B的数量 所以f[i]=max(f[i?1],p[i].a?xx[j]+p[i].b?yy[j])j<i 所以我们要维护这个n^2的递推式 又知道f[i]是由小于

bzoj 4237: 稻草人 -- CDQ分治

4237: 稻草人 Time Limit: 40 Sec  Memory Limit: 256 MB Description JOI村有一片荒地,上面竖着N个稻草人,村民们每年多次在稻草人们的周围举行祭典. 有一次,JOI村的村长听到了稻草人们的启示,计划在荒地中开垦一片田地.和启示中的一样,田地需要满足以下条件: 田地的形状是边平行于坐标轴的长方形: 左下角和右上角各有一个稻草人: 田地的内部(不包括边界)没有稻草人. 给出每个稻草人的坐标,请你求出有多少遵从启示的田地的个数 Input 第一

BZOJ 3262: 陌上花开 cdq分治 树状数组

https://www.lydsy.com/JudgeOnline/problem.php?id=3262 cdq分治板子题,一维排序,一维分治(cdq里的队列),一维数据结构(树状数组). 学dp优化前来复习--以前好像写过这道题但是没写博客啊--在校oj上写的题都没怎么写博客,追悔莫及 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #

bzoj2141: 排队 cdq分治

和动态逆序对有些类似  这题既可以以时间为第一维 也可以以x轴维第一维度   具体视题目而定 cdq分治只能求点对之间的影响  如果要变成整个序列的情况  那么可以用前缀和   一开始的原序列的id设置成0即可 #include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #

[bzoj] 1176 Mokia || CDQ分治

原题 给出W×W的矩阵(S没有用,题目有误),给出无限次操作,每次操作的含义为: 输入1:你需要把(x,y)(第x行第y列)的格子权值增加a 输入2:你需要求出以左下角为(x1,y1),右上角为(x2,y2)的矩阵内所有格子的权值和,并输出 输入3:表示输入结束 因为修改之间相互独立,所以可以用CDQ. 三个维度分别为时间,x轴,y轴. 简单的三维偏序即可. #include<cstdio> #include<algorithm> #define N 100010 #define

bzoj 2141: 排队

就是求个动态区间逆序对??是不是和GTY文艺妹子差不多??哦,不是,,, 这个题的话,可以发现的是,每次交换只会对区间内的数产生影响,所以就是求一下区间内比这个L(区间左端点)大的,小的,(减小,加大)比R(区间右端点)大的,小的,(减大,加小),然后把连个数换一下就就行了..我记得是这样..而且这个sb题也是调了好久... 1 #include<bits/stdc++.h> 2 #define N 100005 3 #define LL long long 4 #define inf 0x3

bzoj 3262: 陌上花开 -- CDQ分治

3262: 陌上花开 Time Limit: 20 Sec  Memory Limit: 256 MB Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb.显然,两朵花可能有同样的属性.需要统计出评出每个等级的花的数量. Input 第一行为N,K (1 <= N <= 100,00

BZOJ 2141 排队 树套树

题目大意:给出一个数列,支持交换两个数字的操作,问每次操作之后的逆序对数量. 思路:数字比较大,先离散化.然后先求一次总逆序对,每次交换两个数字的时候用树套树维护一下逆序对的总数就可以了.. 好像树套树的常数略大,正解应该是分块.. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 20010 using namesp