【bzoj2724】[Violet 6]蒲公英

原创 2015年11月18日 20:39:02

  坑了好久的区间众数……
  思路是分块。
  设块的大小为l,有x个块
  预处理第i个块和第j个块之间的众数和出现次数,这是O(xn)的。
  对于每个询问[l,r],如果l和r在同一个块里面,就暴力查询,这是O(l)的;如果不在同一个块,则先以预处理的信息得到中间连续的块的答案,然后再在最两边的两个块暴力查询每个数在中间出现的次数,然后更新答案。偷懒没多想,写了个主席树,所以是O(llogn)的。
  于是总的复杂度是O(xn+mllogn)
  稍微计算+对拍,取l=100左右的时候可以在时限内跑完。
  

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a,_=b;i<=_;i++)
#define per(i,a,b) for(int i=a,_=b;i>=_;i--)
#define maxn 50007
#define maxb (742)

typedef int arr[maxn];
typedef int blk[maxb];
typedef int seg[maxn * 20];

inline int rd() {
    char c = getchar();
    while (!isdigit(c)) c = getchar() ; int x = c - '0';
    while (isdigit(c = getchar())) x = x * 10 + c - '0';
    return x;
}

int BLOCKS;

seg sz , lc , rc;
arr belong , cnt , a , h , rt;
blk st , ed , ans[maxb] , rec[maxb];
int n_tot , tot , n , m;

void update(int pr , int&nr , int l , int r , int v) {
    if (!nr) nr = ++ n_tot;
    sz[nr] = sz[pr] + 1;
    if (l == r) return;
    int m = (l + r) >> 1;
    if (v <= m)
        rc[nr] = rc[pr] , update(lc[pr] , lc[nr] , l , m , v);
    else
        lc[nr] = lc[pr] , update(rc[pr] , rc[nr] , m + 1 , r , v);
}

int query(int pr , int nr , int l , int r , int v) {
    while (l < r) {
        int m = (l + r) >> 1;
        if (v <= m)
            nr = lc[nr] , pr = lc[pr] , r = m;
        else
            nr = rc[nr] , pr = rc[pr] , l = m + 1;
    }
    return sz[nr] - sz[pr];
}

void input() {
    n = rd() , m = rd();
    rep (i , 1 , n) h[i] = a[i] = rd();
}

void discrete() {
    std::sort(h + 1 , h + n + 1);
    rep (i , 1 , n) a[i] = std::lower_bound(h + 1 , h + n + 1 , a[i]) - h;
    rep (i , 1 , n) update(rt[i - 1] , rt[i] , 1 , n , a[i]);
}

void init_block() {
    BLOCKS = 101;
    rep (i , 1 , n)
        belong[i] = (i - 1) / BLOCKS + 1;
    tot = belong[n];
    rep (i , 1 , tot)
        st[i] = (i - 1) * BLOCKS + 1 , ed[i] = i * BLOCKS;
    rep (i , 1 , tot) {
        int mx = 0 , t = 0;
        rep (j , st[i] , n) {
            cnt[a[j]] ++;
            if (cnt[a[j]] > mx || (cnt[a[j]] == mx && a[j] < t))
                mx = cnt[a[j]] , t = a[j];
            ans[i][belong[j]] = t;
            rec[i][belong[j]] = cnt[t];
        }
        rep (j , st[i] , n)
            cnt[a[j]] = 0;
    }
}

int get_ans(int l , int r) {
    int mx = 0 , t;
    if (belong[l] == belong[r]) {
        rep (i , l , r) cnt[a[i]] = 0;
        rep (i , l , r) cnt[a[i]] ++;
        rep (i , l , r) if (cnt[a[i]] > mx || (cnt[a[i]] == mx && a[i] < t))
            mx = cnt[a[i]] , t = a[i];
    } else {
        if (belong[l] - 1 < belong[r])
            mx = rec[belong[l] + 1][belong[r] - 1] , t = ans[belong[l] + 1][belong[r] - 1];
        rep (i , l , ed[belong[l]]) {
            int c = query(rt[l - 1] , rt[r] , 1 , n , a[i]);
            if (c > mx || (c == mx && a[i] < t))
                t = a[i] , mx = c;
        }
        rep (i , st[belong[r]] , r) {
            int c = query(rt[l - 1] , rt[r] , 1 , n , a[i]);
            if (c > mx || (c == mx && a[i] < t))
                t = a[i] , mx = c;
        }
    }
    return t;
}

void solve() {
    discrete();
    init_block();
    int ans = 0;
    #ifndef ONLINE_JUDGE
        freopen("data.out" , "w" , stdout);
    #endif
    rep (i , 1 , m) {
        int l = (rd() + ans - 1) % n + 1;
        int r = (rd() + ans - 1) % n + 1;
        if (l > r) std::swap(l , r);
        ans = h[get_ans(l , r)];
        printf("%d\n" , ans);
    }
}

int main() {
    #ifndef ONLINE_JUDGE
        freopen("data.txt" , "r" , stdin);
    #endif
    input();
    solve();
    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

BZOJ2724: [Violet 6]蒲公英

裸的分块 不知道可以去看clj写的区间众数 感觉自己常数很大代码也丑的不行。。。 #include #include #include #include #include #in...

【BZOJ 2724】 [Violet 6]蒲公英

分块在线求区间众数~

【BZOJ】【P2724】【Violet 6】【蒲公英】【题解】【分块】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2724 区间众数,分

【Violet 6】【BZOJ2724】蒲公英

Description Input 修正一下l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Samp...

【bzoj2724】[Violet 6]蒲公英

*题目描述: *输入: 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 *输出: *样例输入: 6 ...

[BZOJ2724][Violet 6]蒲公英(分块)

最兴奋的相晤,总是昔日敌手。

BZOJ 2724 [Violet 6] 蒲公英

(在线)分块+离散化

bzoj2724[Violet 6][蒲公英]

BZOJ2724 蒲公英 violet6

BZOJ2724 [Violet 6]蒲公英 解题报告【数据结构】【分块】

BZOJ 2724
  • theljt
  • theljt
  • 2017年07月18日 20:20
  • 90

2724: [Violet 6]蒲公英

题目大意:不带修改的区间众数。 %%%clj大大:区间众数 分块,首先有个重要结论: 摘自clj论文。 分块做。 那么我们就预处理f[i][j],第i块~j块间的众数。 每次枚举最...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【bzoj2724】[Violet 6]蒲公英
举报原因:
原因补充:

(最多只允许输入30个字)