power oj 2885: 连续段

题目链接


  • 题意:给一个长度为 n n n 的排列,m次询问区间 [ l , r ] [l, r] [l,r] 的连续段(相邻的数构成连续段,比如1、2、3;2、3、4)的数目。题目强制在线。
  • 思路:在区间 [ l , r ] [l, r] [l,r] 中,对于区间内任意一个数 x x x 来说,如果它可以作为连续段的起始位,那么它的前驱 x − 1 x - 1 x1 的位置一定在区间 [ l , r ] [l, r] [l,r] 外。所以我们只需要统计,区间内所有元素中前驱的位置在区间 [ l , r ] [l, r] [l,r] 外的元素个数,即是连续段的个数。
    那么反过来,我们也可以求出前驱位置在区间 [ l , r ] [l, r] [l,r] 内的元素个数,区间长度减去即可。所以我们应该怎么求区间中元素前驱位置在 [ l , r ] [l, r] [l,r] 中的元素个数呢?
    可以考虑主席树求某区间值的个数,还可以分块块内排序暴力查找某区间值的个数。分块复杂度算起来是超了的,但是因为强制在线,异或区间导致区间范围变小,所以卡过了。

卡了cout!!!


主席树Code:

#include <bits/stdc++.h>

#define MID (l + r) >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid + 1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr

using namespace std;
typedef long long ll;
const int maxN = 100005;
int read() {
    
    
    int x = 0, f = 1; char ch = getchar();
    while(ch < '0' || ch > '9') {
    
     if(ch == '-') f = -f; ch = getchar(); }
    while(ch >= '0' && ch <= '9') {
    
     x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}

int n, m, a[maxN], id[maxN], pioneer[maxN];
int lastans = 0;
int root[maxN], tot;
struct node{
    
    
    int ls, rs, num;
}tree[maxN * 20];
void update(int &now, int pre, int l, int r, int k) {
    
    
    now = ++ tot;
    tree[now] = tree[pre];
    tree[now].num ++ ;
    if(l == r) return ;
    int mid = MID;
    if(mid >= k) update(tree[now].ls, tree[pre].ls, l, mid, k);
    else update(tree[now].rs, tree[pre].rs, mid + 1, r, k);
}
int query(int i, int j, int l, int r, int ql, int qr) {
    
     //区间[i + 1, j]中有多少值在[ql, qr]之间的数
    if(ql <= l && qr >= r) return tree[j].num - tree[i].num;
    int mid = MID;
    if(qr <= mid) return query(tree[i].ls, tree[j].ls, l, mid, ql, qr);
    else if(ql > mid) return query(tree[i].rs, tree[j].rs, mid + 1, r, ql, qr);
    else return query(tree[i].ls, tree[j].ls, l, mid, ql, qr) + query(tree[i].rs, tree[j].rs, mid + 1, r, ql, qr);
}
map<pair<int, int>, int>mp;
int main() {
    
    
    n = read();
    for(int i = 1; i <= n; ++ i ) {
    
    
        a[i] = read();
        id[a[i]] = i;
    }
    for(int i = 1; i <= n; ++ i ) {
    
    
        pioneer[i] = id[a[i] - 1];
    }
    int UP = n;
    for(int i = 1; i <= n; ++ i ) {
    
    
        update(root[i], root[i - 1], 0, UP, pioneer[i]);
    }
    m = read();
    while(m -- ) {
    
    
        int l, r; l = read(), r = read();
        l = l ^ lastans, r = r ^ lastans;
        if(l < 1 || r > n || l > r) continue;
        if(mp.find(make_pair(l, r)) != mp.end()) {
    
    
            lastans = mp[make_pair(l, r)];
        } else {
    
    
            lastans = r - l + 1 - query(root[l - 1], root[r], 0, UP, l, r);
            mp[make_pair(l, r)] = lastans;
        }
        printf("%d\n", lastans);
//        cout << lastans << endl;
    }
    return 0;
}

分块Code:

#include <bits/stdc++.h>
using namespace std;

const int maxN = 100005;

int read() {
    
    
    int x = 0, f = 1; char ch = getchar();
    while(ch < '0' || ch > '9') {
    
     if(ch == '-') f = -f; ch = getchar(); }
    while(ch >= '0' && ch <= '9') {
    
     x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
int n, m;
int a[maxN], id[maxN];
int pre[maxN];
int lastans = 0;
int block[maxN], blockNum;
vector<int>vt[maxN];
void Force(int l, int r, int L, int R, int &ans) {
    
    
    for(int i = l; i <= r; ++ i ) {
    
    
        if(pre[i] > R || pre[i] < L) ++ ans;
    }
}
int query(int l, int r) {
    
    
    int ans = 0;
    if(block[l] == block[r]) {
    
    
        Force(l, r, l, r, ans);
    } else {
    
    
        Force(l, block[l] * blockNum, l, r, ans);
        Force((block[r] - 1) * blockNum + 1, r, l, r, ans);
        for(int i = block[l] + 1; i <= block[r] - 1; ++ i ) {
    
    
            ans += lower_bound(vt[i].begin(), vt[i].end(), l) - vt[i].begin();
            ans += (blockNum - (upper_bound(vt[i].begin(), vt[i].end(), r) - vt[i].begin()));
        }
    }
    return ans;
}
int main() {
    
    
    n = read();
    blockNum = sqrt(n);
    for(int i = 1; i <= n; ++ i ) {
    
    
        a[i] = read();
        id[a[i]] = i;
    }
    for(int i = 1; i <= n; ++ i ) {
    
    
        pre[i] = id[a[i] - 1];
        block[i] = (i - 1) / blockNum + 1;
        vt[block[i]].emplace_back(pre[i]);
    }
    for(int i = 1; i <= block[n]; ++ i ) {
    
    
        sort(vt[i].begin(), vt[i].end());
    }
    m = read();
    while(m -- ) {
    
    
        int l, r;
        l = read() ^ lastans, r = read() ^ lastans;
        if(l < 1 || r > n || l > r) continue;
        lastans = query(l, r);
//        cout << lastans << endl;
        printf("%d\n", lastans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/108775202