1. 程式人生 > >【LOJ】#2275. 「JXOI2017」顏色

【LOJ】#2275. 「JXOI2017」顏色

n) push_back AS 隊列 int In con pla class

題解

我們枚舉右端點判斷合法的左端點有哪些

首先,記錄一下右端點右邊的點的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(); } }

【LOJ】#2275. 「JXOI2017」顏色