小美的彩带

莫队算法,也可以用主席树,好像还能用树状数组乱搞?

#include <iostream>
#include <cmath>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 4e5 + 10;
int a[N];
int n, q, L;


struct Interval {
    int l, r, id, index, num, flag;
    bool operator < (const Interval& p) const {
        if (id != p.id) return id < p.id;
        return (id & 1) ? r < p.r : r > p.r;
    }
} I[N];

bool cmp(const Interval &a, const Interval &b) {
    return a.index < b.index;
}

int mp[N];
int main() 
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> q;
    L = sqrt(2*n);
    
    for(int i = 1; i <= n; i++) cin >> a[i];
    vector<int> vals;
    for (int i = 1; i <= n; i++) vals.push_back(a[i]);
    sort(vals.begin(), vals.end());
    vals.erase(unique(vals.begin(), vals.end()), vals.end());
    int cc = vals.size();
    for (int i = 1; i <= n; i++) {
        a[i] = lower_bound(vals.begin(), vals.end(), a[i]) - vals.begin() + 1;
        a[i + n] = a[i];
    }
    int l = 0, r = 0;
    for(int i = 1; i <= q; i++) {
        char ch; int x; cin >> ch >> x;
        if(x >= n) { 
            I[i].flag = true; 
            if(ch == 'L') l = (l + x) % n;
            else r = (r + x) % n;
            continue; 
        }
        else I[i].flag = false;
        if(ch== 'L') {
            I[i].l = (l + 1) % n; if(!I[i].l) I[i].l = n;
            I[i].r = (I[i].l + x - 1);
            l = (l + x) % n;
            // cout << I[i].l << " L " << I[i].r << endl;
        } 
        else {
           I[i].r = ((n - r) % n + n) % n + n;
           I[i].l = (I[i].r - x + 1);
           r = (r + x) % n;
        //    cout << I[i].l << " R " << I[i].r << endl;
        }
    }

    for(int i = 1; i <= q; i++) {
        I[i].id = I[i].l / L;
        I[i].index = i;
    }
    sort(I + 1, I + q + 1);
    // for(int i = 1; i <= q; i++) cout << I[i].l << ' ' << I[i].r << " " << I[i].flag << endl;
    int cnt = 0, ok = false;
    int lst = -1;
    for(int i = 1; i <= q; i++) {
        if(I[i].flag) continue;
        // if(I[i].l > I[i].r) cout << " ??? " << endl;
        if(!ok) { // I[i].id != I[lst].id
            ok = true;
            memset(mp, 0, sizeof(mp));
            cnt = 0;
            for(int j = I[i].l; j <= I[i].r; j++) {
                if(!mp[a[j]]) cnt++;
                mp[a[j]]++;
            }
            I[i].num = cnt;
        }
        else {
            for(int j = I[lst].r; j > I[i].r; j--) {
                if(--mp[a[j]] == 0) {
                    cnt--;
                }
            }
            for(int j = I[lst].r + 1; j <= I[i].r; j++) {
                if(!mp[a[j]]) cnt++;
                mp[a[j]]++;
            }
            for(int j = I[lst].l; j < I[i].l; j++) {
                if(--mp[a[j]] == 0) {
                    cnt--;
                }
            }
            for(int j = I[lst].l - 1; j >= I[i].l; j--) {
                if(!mp[a[j]]) cnt++;
                mp[a[j]]++;
            }
            I[i].num = cnt;
        }
        lst = i;
    }
    sort(I + 1, I + q + 1, cmp);
    // for(int i = 1; i <= q; i++) cout << I[i].l << ' ' << I[i].r << endl; 
    for(int i = 1; i <= q; i++) {
        if(I[i].flag) printf("%d\n", cc);
        else printf("%d\n", I[i].num);
    }
}
// 64 位输出请用 printf("%lld")


// 10 10
// 4 5 3 10 4 7 10 5 4 8
// L 8
// R 4
// L 3
// L 4
// L 1
// L 3
// R 4
// R 3
// L 10
// L 10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值