【LOJ】#2275. 「JXOI2017」颜色

题解

我们枚举右端点判断合法的左端点有哪些

首先,记录一下右端点右边的点的pre,也就是这个数字前一个出现的位置,取所有小于枚举右端点r的值中最大的一个做为l,用优先队列维护即可,[l + 1,r]就是可能取到的左端点的区间

然后我们对于每一种数字,最前一次出现的位置p,最后一次出现的位置q,覆盖[p + 1,q]这段区间作为不能填的区间,用线段树维护一下,用可取的左端点区间减掉不能填的地方

如果右端点出现过了,那么删除这种数字的覆盖区间,可以在右端点左移的时候同时干这件事

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#include <bitset>
#include <queue>
#define enter putchar('\n')
#define space putchar(' ')
//#define ivorysi
#define pb push_back
#define mo 974711
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define MAXN 200005
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 - '0' + c;
    c = getchar();
    }
    res = res * f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) out(x / 10);
    putchar('0' + x % 10);
}
int N;
int a[MAXN],minn[MAXN],maxx[MAXN],pre[MAXN],last[MAXN],vis[MAXN];
int64 ans;
priority_queue<int> Q;
struct node {
    int l,r,cover,sum;
}tr[MAXN * 4];
void build(int u,int l,int r) {
    tr[u].l = l;tr[u].r = r;
    tr[u].cover = 0;tr[u].sum = 0;
    if(l == r) return;
    int mid = (l + r) >> 1;
    build(u << 1,l,mid);
    build(u << 1 | 1,mid + 1,r);
}
void addcover(int u,int v) {
    tr[u].cover += v;
    if(tr[u].cover) tr[u].sum = tr[u].r - tr[u].l + 1;
    else tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void update(int u) {
    if(tr[u].cover) tr[u].sum = tr[u].r - tr[u].l + 1;
    else tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void Add(int u,int l,int r,int on) {
    if(l > r) return;
    if(tr[u].l == l && tr[u].r == r) {
    addcover(u,on);
    return;
    }
    int mid = (tr[u].l + tr[u].r) >> 1;
    if(r <= mid) Add(u << 1,l,r,on);
    else if(l > mid) Add(u << 1 | 1,l,r,on);
    else Add(u << 1,l,mid,on),Add(u << 1 | 1,mid + 1,r,on);
    update(u);
}
int Query(int u,int l,int r) {
    if(tr[u].cover) return r - l + 1;
    if(tr[u].l == l && tr[u].r == r) return tr[u].sum;
    int mid = (tr[u].l + tr[u].r) >> 1;
    if(r <= mid) return Query(u << 1,l,r);
    else if(l > mid) return Query(u << 1 | 1,l,r);
    else return Query(u << 1,l,mid) + Query(u << 1 | 1,mid + 1,r);
}
void Solve() {
    while(!Q.empty()) Q.pop();
    read(N);
    build(1,1,N);
    ans = 0;
    for(int i = 1 ; i <= N ; ++i) {
    read(a[i]);
    minn[i] = N;maxx[i] = 0;
    pre[i] = 0;last[i] = 0;
    }
    for(int i = 1 ; i <= N ; ++i) {
    minn[a[i]] = min(minn[a[i]],i);
    maxx[a[i]] = max(maxx[a[i]],i);
    }
    for(int i = 1 ; i <= N ; ++i) {
    if(!vis[a[i]]) {
        Add(1,minn[a[i]] + 1,maxx[a[i]],1);
        vis[a[i]] = 1;
    }
    }
    for(int i = 1 ; i <= N ; ++i) {
    pre[i] = last[a[i]];
    last[a[i]] = i;
    }
    Q.push(0);
    for(int i = N ; i >= 1 ; --i) {
    while(Q.top() > i) Q.pop();
    int L = Q.top() + 1;
    if(L <= i) {
        int t = i - L + 1;
        ans += t - Query(1,L,i);
    }
    Q.push(pre[i]);
    if(vis[a[i]]) {
        Add(1,minn[a[i]] + 1,maxx[a[i]],-1);
        vis[a[i]] = 0;
    }
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    int T;
    read(T);
    while(T--) {
    Solve();
    }
}

猜你喜欢

转载自www.cnblogs.com/ivorysi/p/9200644.html