关于分块长度的问题

P4168 [Violet] 蒲公英

Rintaro @ 2019-03-15 21:09:06

lyd书上的第二种做法 复杂度O(NT+MN/T*logN),取T = sqrt(NlogN) 但我在实际实现时,分块长度按这么取就T了,我调参的时候,发现长度取到100以下反而能快。。取到50以下就A掉了此题,也许是我实现错了?

#include <iostream>
#include <cstdio>
#include <climits>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <cmath>

#define readint(x) scanf("%d",&(x))
#define putint(x) printf("%d\n",(x))
#define lowbit(x) ((x)&(-(x)))
#define mp(x,y) make_pair((x),(y))
#define lint long long
#define rint register int
#define ldob long double

using namespace std;
const int maxn = 50000 + 10;
const int maxlen = 3000;
int n, m, len, t;
int arr[maxn], preans[maxlen][maxlen][2];
int cnt[maxn], htval[maxn];
int ht[maxn], tot = 0;
vector<int> mem[maxn];

// 1 3 3 5 6 7 9
inline int ask(int val, int l, int r){ // 返回L,R范围内有多少个val 
    int i = lower_bound(mem[val].begin(),mem[val].end(),l) - mem[val].begin(),
        j = upper_bound(mem[val].begin(),mem[val].end(),r) - mem[val].begin() - 1;
    return j - i + 1;
}
// 计算x属于哪段 
inline int eco(int x){
    return (x-1) / len + 1;
}

int main(){
//  freopen("testdata.in","r",stdin);
//  freopen("ans.out","w",stdout);
    readint(n), readint(m);
    len = min((int)sqrt(n),20), t = ceil((double)n/len);
    for(rint i=1; i<=n; i++) readint(arr[i]), ht[i] = arr[i];

    sort(ht+1,ht+n+1);
    tot = unique(ht+1,ht+n+1) - (ht+1);
    for(rint i=1; i<=n; i++) {
        int val = arr[i];
        arr[i] = lower_bound(ht+1,ht+tot+1,val) - ht;
        htval[arr[i]] = val;
        mem[arr[i]].push_back(i);
    }

    for(rint lt=1; lt<t; lt++){ // 枚举左端点 
        int nowans = 0;
        memset(cnt,0,sizeof(cnt));
        for(rint j=(lt-1)*len+1; j<=n; j++){
            cnt[arr[j]]++;
            if(cnt[arr[j]] > cnt[nowans] || (cnt[arr[j]] == cnt[nowans] && htval[nowans] > htval[arr[j]])) nowans = arr[j]; // >保证编号最小 
            if(j % len == 0) preans[lt][j/len][0] = nowans, preans[lt][j/len][1] = cnt[nowans];
            if(j == n) preans[lt][t][0] = nowans, preans[lt][t][1] = cnt[nowans];
        }
    }

    memset(cnt,0,sizeof(cnt));
    int l, r, x = 0;
    while(m--){
        scanf("%d %d",&l,&r);
        l = (l+x-1) % n + 1, r = (r+x-1) % n + 1;
        if(l > r) swap(l,r);

        int lt = eco(l), rt = eco(r), ans = 0, nmax = 0;
        if(rt - lt <= 1){
            for(rint i=l; i<=r; i++) cnt[arr[i]]++;
            for(rint i=l; i<=r; i++) {
                if(cnt[arr[i]] > nmax || (cnt[arr[i]] == nmax && htval[ans] > htval[arr[i]])){
                    ans = arr[i], nmax = cnt[arr[i]];
                }
            }
            for(rint i=l; i<=r; i++) cnt[arr[i]]--;
        }else {
            ans = preans[lt+1][rt-1][0], nmax = preans[lt+1][rt-1][1];
            for(rint i=l; i<=lt*len; i++) {
                int lans = ask(arr[i],l,r);
                if(nmax < lans || (nmax == lans && htval[ans] > htval[arr[i]])) ans = arr[i], nmax = lans; //输出编号最小 
            }
            for(rint i=(rt-1)*len+1; i<=r; i++){
                int rans = ask(arr[i],l,r);
                if(nmax < rans || (nmax == rans && htval[ans] > htval[arr[i]])) ans = arr[i], nmax = rans;
            }
        }
        x = htval[ans];
        printf("%d\n",x);
    }

    return 0;
}
/*
    for(rint i=1; i<=n; i++){
        readint(arr[i]);
        if(htdex.find(arr[i]) == htdex.end()) { //不存在 
            htdex[arr[i]] = i;
            htval[i] = arr[i];
        }
        arr[i] = htdex[arr[i]];
        mem[arr[i]].push_back(i); // 存下标 vector从0开始 
    }
*/

by 花里心爱 @ 2019-03-15 21:48:22

这似乎是每个操作常数不相等带来的问题?qwq


by noip @ 2019-03-16 08:05:35

写线性空间的nsqrtn做法啊

多好啊


by shadowice1984 @ 2019-03-28 21:00:33

写线性空间的nsqrtn做法啊

多好啊

都9120年了区间众数还要带log的吗……


|