Continuous Intervals【單調棧】【合法區間計數】

題目鏈接:https://nanti.jisuanke.com/t/41296

從左到右枚舉右端點,然後求合法的左端點的個數。

用max表示區間最大值,min表示區間最小值,cnt表示區間不同數的個數。

合法需要滿足max-min-cnt == -1

用單調棧可以找到每次添加右端點後,最大值和最小值需要更新的區間。(都是以R爲右端點)

用unordered_map可以找到區間內不同數的個數需要更新的區間。

然後用線段樹進行維護就可以了。

#include <bits/stdc++.h>
#define rep(i ,a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define mid (l+r>>1)
#define lson (o<<1)
#define rson (o<<1|1)
#define ll long long
using namespace std;
const int N = 1e5+100;
stack<int> st_max,st_min;
int s[N];
unordered_map<int,int> pos;
struct node{
    int data,num,lazy;
}tree[4*N];
void up(int o){
    tree[o].data = min(tree[lson].data , tree[rson].data);
    tree[o].num = 0;
    if(tree[lson].data==tree[o].data) tree[o].num += tree[lson].num;
    if(tree[rson].data==tree[o].data) tree[o].num += tree[rson].num;
}
void build(int o,int l,int r){
    tree[o].lazy = 0;
    if(l==r) {
        tree[o].data = 0;
        tree[o].num = 1;
        return;
    }
    build(lson,l,mid);
    build(rson,mid+1,r);
    up(o);
}
void down(int o){
    int lazy = tree[o].lazy;
    tree[lson].data += lazy;
    tree[lson].lazy += lazy;
    tree[rson].data += lazy;
    tree[rson].lazy += lazy;
    tree[o].lazy = 0;
}
int query(int o,int l,int r,int h,int t){
    if(l>=h&&r<=t) {
        if(tree[o].data==-1) return tree[o].num;
        else return 0;
    }
    int ans=0;
    if(tree[o].lazy) down(o);
    if(mid>=h) ans+=query(lson,l,mid,h,t);
    if(mid<t)  ans+=query(rson,mid+1,r,h,t);
    return ans;
}
void add(int o,int l,int r,int h,int t,int data){
    if(h>t) return;
    if(l>=h&&r<=t) {
        tree[o].lazy += data;
        tree[o].data += data;
        return ;
    }
    if(tree[o].lazy) down(o);
    if(mid>=h) add(lson,l,mid,h,t,data);
    if(mid<t)  add(rson,mid+1,r,h,t,data);
    up(o);
}
int main() {
    int T;
    scanf("%d",&T);
    int cas = 0;
    while(T--) {
        cas++;
        int n;
        scanf("%d",&n);
        build(1,1,n);
        pos.clear();
        ll ans = 0;
        while(!st_max.empty()) st_max.pop();
        while(!st_min.empty()) st_min.pop();
        st_max.push(0);
        st_min.push(0);
        rep(i, 1, n) {
            add(1,1,n,i,i,-1);
            scanf("%d",&s[i]);
            int l=i,r;
            while(st_min.size()>=2&&s[i]<=s[st_min.top()]) {
                r = l-1;
                l = st_min.top()+1;
                st_min.pop();
                add(1,1,n,l,r,s[r]-s[i]);
            }
            if(!st_min.empty()) {
                r = l-1;
                l = st_min.top()+1;
                add(1,1,n,l,r,s[r]-s[i]);
            }
            st_min.push(i);
            l = i;
            while(st_max.size()>=2&&s[i]>=s[st_max.top()]) {
                r = l-1;
                l = st_max.top()+1;
                st_max.pop();
                add(1,1,n,l,r,s[i]-s[r]);
            }
            if(!st_max.empty()) {
                r = l-1;
                l = st_max.top()+1;
                add(1,1,n,l,r,s[i]-s[r]);
            }
            st_max.push(i);
            add(1,1,n,pos[s[i]]+1,i-1,-1);
            pos[s[i]] = i;
            ans += query(1,1,n,1,i);
        }
        printf("Case #%d: %lld\n",cas,ans);
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章