G. Three Occurrences(问有多少个子序列(连续)满足所有值只出现确切3次。)

题:https://codeforces.com/contest/1418/problem/G

题意:给定n(n<=5e5)的序列,问有多少个子序列(连续)满足所有值只出现确切3次。

分析:总操作:枚举左端点,查看多少个满足的右端点;

   对于某个值,要么不出现,要么只出现3次,那么对于当前枚举的左端点的值a[l],合法区间肯定就是之前累计过的第2次出现到第3次出现的位置之间(不包含第3次出现的位置);

   那么设对于每个合法区间的右端点我们标记为0,那么答案就是0的个数;

   首先没出现一次都让[i,pos[ a[i] ].size()-1] ]内先假设不合法,那么到第2,第3次的时候加回-1让其为0变合法,统计0最小值个数。

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define MP make_pair
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
typedef long long ll;
const int M=5e5+6;
const int inf=0x3f3f3f3f;
const ll INF=1e18;
vector<int>pos[M];
int a[M];
struct SegTree{
    int tr[M<<2],cnt[M<<2],lz[M<<2];
    void up(int root){
        tr[root]=min(tr[root<<1],tr[root<<1|1]);
        cnt[root]=0;
        if(tr[root]==tr[root<<1])
            cnt[root]=cnt[root<<1];
        if(tr[root]==tr[root<<1|1])
            cnt[root]+=cnt[root<<1|1];
    }
    void pushdown(int root){
        if(lz[root]){
            tr[root<<1]+=lz[root];
            tr[root<<1|1]+=lz[root];
            lz[root<<1]+=lz[root];
            lz[root<<1|1]+=lz[root];
            lz[root]=0;
        }
    }
    void build(int root,int l,int r){
        lz[root]=0;
        if(l==r){
            tr[root]=0;
            cnt[root]=1;
            return ;
        }
        int midd=(l+r)>>1;
        build(lson);
        build(rson);
        up(root);
    }
    void update(int L,int R,int val,int root,int l,int r){
        if(L<=l&&r<=R){
            tr[root]+=val;
            lz[root]+=val;
            return ;
        }
        int midd=(l+r)>>1;
        pushdown(root);
        if(L<=midd)
            update(L,R,val,lson);
        if(R>midd)
            update(L,R,val,rson);
        up(root);
    }
    int query(int L,int R,int root,int l,int r){
        if(L<=l&&r<=R){
            return tr[root]==0 ? cnt[root] : 0;
        }
        pushdown(root);
        int midd=(l+r)>>1;
        int res=0;
        if(L<=midd)
            res=query(L,R,lson);
        if(R>midd)
            res+=query(L,R,rson);
        return res;
    }
}t1;
int getid(int u,int x){
    return pos[u][pos[u].size()-x];
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    t1.build(1,1,n);
    for(int i=1;i<=n;i++)
        pos[i].pb(n+1);
    ll ans=0;
    for(int i=n;i>=1;i--){
        ///1位置
        if(pos[a[i]].size()>=4){///让之前2位置的合法区间无效
            t1.update(getid(a[i],3),getid(a[i],4)-1,1,1,1,n);
        }
        pos[a[i]].pb(i);
        ///2位置
        if(pos[a[i]].size()>=4){///抵消掉下方之前位置3的操作,让合法区间有效
            t1.update(getid(a[i],3),getid(a[i],4)-1,-1,1,1,n);
        }
        /*for(auto it:pos[a[i]])
            cout<<it<<' ';
        cout<<endl;*/
        ///3位置
        t1.update(i,getid(a[i],2)-1,1,1,1,n);///先假设区间无效
        ans+=t1.query(i,n,1,1,n);
    }
    printf("%lld\n",ans);
    return 0;
}
/***
10 9
10 9 8
10 9 8 7
10 6
10 6 5
10 9 8 7 4
10 9 8 7 4 3
10 9 8 7 4 3 2
10 6 5 1
***/
View Code

 

posted @ 2020-09-22 13:57  starve_to_death  阅读(252)  评论(0编辑  收藏  举报