码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj5011: [Jx2017]颜色

时间:2017-09-10 19:01:18      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:sizeof   --   main   print   out   std   pre   序列   有一个   

Description

可怜有一个长度为n的正整数序列Ai,其中相同的正整数代表着相同的颜色。
现在可怜觉得这个序列太长了,于是她决定选择一些颜色把这些颜色的所有位置都删去。
删除颜色i可以定义为把所有满足Aj=i的位置j都从序列中删去。
然而有些时候删去之后,整个序列变成了好几段,可怜不喜欢这样,于是她想要知道有多
少种删去颜色的方案使得最后剩下来的序列非空且连续。
例如颜色序列{1,2,3,4,5},删除颜色3后序列变成了{1,2}和{4,5}两段,不满足条件。
而删除颜色1后序列变成了{2,3,4,5},满足条件。
两个方案不同当且仅当至少存在一个颜色i只在其中一个方案中被删去 。

Input

第一行输入一个整数T表示数据组数。
每组数据第一行输入一个整数n表示数列长度。
第二行输入n个整数描述颜色序列。
1 ≤ T, ∑ n ≤ 3 × 10^5, 1 ≤ Ai ≤ n

Output

对于每组数据输出一个整数表示答案
对每种颜色,只能全选或全不选,将区间[L,R]看作平面上的点(L,R),则限制条件是矩形内的点不能选,可以用线段树维护扫描线进行统计。
#include<bits/stdc++.h>
char buf[10000007],*ptr=buf;
int _(){
    int x=0;
    while(*ptr<48)++ptr;
    while(*ptr>47)x=x*10+*ptr++-48;
    return x;
}
const int N=3e5+7;
int T,n;
int a[N],pe[N],pb[N],pv[N],nx[N];
long long ans;
int min(int a,int b){return a<b?a:b;}
int _l,_r,_a;
struct node{
    node*lc,*rc;
    int L,R,M;
    int mn,mt,a;
    void add(int x){
        mn+=x,a+=x;
    }
    void dn(){
        if(a){
            lc->add(a);
            rc->add(a);
            a=0;
        }
    }
    void up(){
        mn=min(lc->mn,rc->mn);
        mt=(mn==lc->mn?lc->mt:0)+(mn==rc->mn?rc->mt:0);
    }
    void add(){
        if(_l<=L&&R<=_r)return add(_a);
        dn();
        if(_l<=M)lc->add();
        if(_r>M)rc->add();
        up();
    }
    int c0(){
        return mn?0:mt;
    }
}ns[N*2],*np,*rt;
node*build(int L,int R){
    node*w=np++;
    w->L=L,w->R=R;
    w->mn=w->a=w->M=0;
    w->mt=R-L+1;
    if(L<R){
        int M=w->M=L+R>>1;
        w->lc=build(L,M);
        w->rc=build(M+1,R);
    }
    return w;
}
void add(int l,int r,int a){
    _l=l,_r=r,_a=a;
    if(l<=r)rt->add();
}
int main(){
    fread(buf,1,sizeof(buf),stdin);
    for(T=_();T;--T){
        n=_();ans=0;
        np=ns;
        rt=build(1,n);
        for(int i=1;i<=n;++i)a[i]=_(),pe[i]=0,pb[i]=n+1;
        for(int i=1,x;i<=n;++i)x=a[i],pv[i]=pe[x],pe[x]=i;
        for(int i=n,x;i>=1;--i)x=a[i],nx[i]=pb[x],pb[x]=i;
        add(1,n,1);
        for(int i=n,x;i;--i){
            x=a[i];
            add(i+1,nx[i]-1,1);
            if(i==pb[x])add(pe[x],n,-1);
            ans+=rt->c0();
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

bzoj5011: [Jx2017]颜色

标签:sizeof   --   main   print   out   std   pre   序列   有一个   

原文地址:http://www.cnblogs.com/ccz181078/p/7501631.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!