bzoj 3289 莫队 逆序对

莫队维护逆序对,区间左右增减要分类讨论。

记得离散化。

  1 /**************************************************************
  2     Problem: 3289
  3     User: idy002
  4     Language: C++
  5     Result: Accepted
  6     Time:5480 ms
  7     Memory:3164 kb
  8 ****************************************************************/
  9
 10 #include <cstdio>
 11 #include <cstring>
 12 #include <cmath>
 13 #include <algorithm>
 14 #define maxn 50010
 15 #define lowbit(i) ((i)&(-(i)))
 16 using namespace std;
 17
 18 typedef long long lng;
 19
 20 int n, m;
 21 int disc[maxn];
 22 int lx[maxn], rx[maxn], mccno[maxn], stot;
 23 int w[maxn];
 24 lng cnt[maxn], cnttot, cur_ans;
 25 lng ans[maxn];
 26
 27 struct Qu {
 28     int l, r, id;
 29     bool operator<( const Qu & b ) const {
 30         return mccno[l]<mccno[b.l] || (mccno[l]==mccno[b.l] && r<b.r );
 31     }
 32 };
 33 Qu qu[maxn];
 34
 35 lng qu_pres( int r ) {
 36     lng rt = 0;
 37     for( int i=r; i; i-=lowbit(i) )
 38         rt += cnt[i];
 39     return rt;
 40 }
 41 void up_val( int pos, int delta ) {
 42     for( int i=pos; i<=n; i+=lowbit(i) )
 43         cnt[i] += delta;
 44     cnttot += delta;
 45 }
 46 void push_back( int pos ) {
 47     cur_ans += cnttot - qu_pres( pos );
 48     up_val( pos, +1 );
 49 }
 50 void pop_back( int pos ) {
 51     cur_ans -= cnttot - qu_pres( pos );
 52     up_val( pos, -1 );
 53 }
 54 void push_front( int pos ) {
 55     cur_ans += qu_pres( pos-1 );
 56     up_val( pos, +1 );
 57 }
 58 void pop_front( int pos ) {
 59     cur_ans -= qu_pres( pos-1 );
 60     up_val( pos, -1 );
 61 }
 62
 63 void partition() {
 64     int len = (int)ceil(sqrt(n))+1;
 65     int stot = n/len;
 66     rx[0] = 0;
 67     for( int i=1; i<=stot; i++ ) {
 68         lx[i] = rx[i-1]+1;
 69         rx[i] = rx[i-1]+len;
 70     }
 71     if( rx[stot]!=n ) {
 72         stot++;
 73         lx[stot] = rx[stot-1]+1;
 74         rx[stot] = n;
 75     }
 76     for( int i=1; i<=stot; i++ )
 77         for( int j=lx[i]; j<=rx[i]; j++ )
 78             mccno[j] = i;
 79 }
 80 void work() {
 81     sort( qu+1, qu+1+m );
 82     int lf, rg;
 83     for( int q=1; q<=m; q++ ) {
 84         if( q==1 || mccno[qu[q].l] != mccno[qu[q-1].l] ) {
 85             lf = qu[q].l;
 86             rg = qu[q].l-1;
 87             memset( cnt, 0, sizeof(cnt) );
 88             cur_ans = cnttot = 0;
 89         }
 90         while( lf<qu[q].l ) pop_front( w[lf++] );
 91         while( lf>qu[q].l ) push_front( w[--lf] );
 92         while( rg<qu[q].r ) push_back( w[++rg] );
 93         while( rg>qu[q].r ) pop_back( w[rg--] );
 94         ans[qu[q].id] = cur_ans;
 95     }
 96 }
 97 int main() {
 98     scanf( "%d", &n );
 99     for( int i=1; i<=n; i++ ) {
100         scanf( "%d", w+i );
101         disc[i] = w[i];
102     }
103     sort( disc+1, disc+1+n );
104     for( int i=1; i<=n; i++ )
105         w[i] = lower_bound( disc+1, disc+1+n, w[i] ) - disc;
106     scanf( "%d", &m );
107     for( int i=1; i<=m; i++ ) {
108         scanf( "%d%d", &qu[i].l, &qu[i].r );
109         qu[i].id = i;
110     }
111     partition();
112     work();
113     for( int i=1; i<=m; i++ )
114         printf( "%lld\n", ans[i] );
115 }

时间: 2024-10-14 09:57:42

bzoj 3289 莫队 逆序对的相关文章

主席树初探 &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]动态逆序对

Description 对于序列A,它的逆序对数定义为满足iAj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数 Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数. 以下n行每行包含一个1到n之间的正整数,即初始排列. 以下m行每行一个正整数,依次为每次删除的元素. N<=100000 M<=50000 Output 输出包含m行,依次为删除每个元素之前,逆序对的个数. Sample In

bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)

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

bzoj 2038 莫队入门

http://www.lydsy.com/JudgeOnline/problem.php?id=2038 题意:多次询问区间内取出两个相同颜色的种类数 思路:由于不是在线更新,那么可以进行离线查询,而且当知道了[l,r]的答案,且能在O(1)的条件下得知[l-1,r],[l+1,r],[l,r+1],[l,r-1]的答案,那么就能使用莫队算法了. 大致上,将区间分块,由于n=a+b>=a*b,显然将区间开平方根是最优的,我们先将询问保存,按照块序第一优先,再考虑右端点进行排序.再来,使用cnt[

bzoj 3809 莫队

收获: 1.分块时顺便记录每个位置所属的块,然后一次排序就OK了. 2.要权衡在“区间移动”与“查询结果”之间的时间,莫队算法一般区间移动频率远大于查询结果,所以我们选择的辅助数据结构时就要注意了,我最开始写的是值域线段树,自己生成的极限数据要1m8s,改成树状数组后要24s,还是过不了,hzwer只要13s,细看hzwer的代码,发现Ta用的是分块,O(1)修改O(n0.5)查询,改成分块后的确快多了. 3.块的大小理论最优值是O(n*m-0.5),最开始设成这个交上去35卡过,改成hzwer

bzoj 3295: [Cqoi2011]动态逆序对

2016-06-22 这个题本想昨天晚上做来,但昨晚狂风大作,暴雨倾盆(听说我们学校最落后的一堵墙都被吹到了),停电了,我只能无聊的瞭望了教学楼一晚上...... 这个题把删除看成插入的话,插入一个点 新增逆序对就是比他早插入的,位置靠前,数比他大或 位置靠后,数比他小.那这就是个三维偏序集,可以用CDQ搞搞了. 这个题也能用树套树,树状数组归并排序做(以后有时间要写一写,恐怕是没可能了%>_<%). 1 #include<cstdio> 2 #include<iostrea

BZOJ 3339 &amp; 莫队+&quot;所谓的暴力&quot;

题意: 给一段数字序列,求一段区间内未出现的最小自然数. SOL: 框架显然用莫队.因为它兹瓷离线. 然而在统计上我打了线段树...用&维护的结点...400w的线段树...然后二分查找...炸的妥妥的... 然后发现所谓的"暴力"...直接开数组维护...因为指针具有一定的单调性,一次更改可以直接得到解,不用每次都查询... woc真是...有时候数据结构用多了忽略了那些更简单更实用的方法... Code TLE的代码: /*=========================

COGS 1715 &amp; bzoj 3295 [CQOI2011]动态逆序对 题解

(又是一道树套树……自己真是玩疯了……) (题意略) 从网上也看过题解,好像解法很多……比如CDQ+树状数组,树状数组套主席树,树状数组套平衡树……我用的是树状数组套splay. (我会说是因为我不会写CDQ和树状数组套主席树么= =) (不得不吐槽,为啥splay这么快= =) 也没啥可说的,我写的是在线算法,只要在删除一个元素之前统计它前面比它大的数和后面比它小的数的个数(区间求和用树状数组,统计比它小/大的数的个数用平衡树写),把答案减掉对应数值即可. 鉴于这题卡常,我就加了快读和各种in

BZOJ 3295: [Cqoi2011]动态逆序对 cdq分治

https://www.lydsy.com/JudgeOnline/problem.php?id=3295 这个妹妹我曾见过的~~~ 之前应该在校内oj写了,似乎还写过题解?发现没写博客就重新水一遍代码水一篇博客好了. 把找逆序对的过程想成一个一个往里塞数字然后找每个数字可以组成的逆序对,把最后要去掉的几个也想成往里塞,所以加一个时间维度用cdq求三维偏序. 1 #include<iostream> 2 #include<cstdio> 3 #include<algorith