JXOI2017颜色 解题报告

JXOI2017颜色

  • 首先记录每个位置上颜色在序列中上次出现的位置
  • 开两颗线段树,第一棵维护区间最大值,实际上是维护当前必须被删去的颜色的位置的最大值,第二棵则是维护区间和
  • 首先倒着扫一遍,对于当前颜色的后面一个颜色,将其删去,那他的\(pre\)肯定也要删去,将其\(pre\)的位置加入第一棵线段树,对每个位置记一个\(able\),值为当前第一棵线段树中最大值,表示当前点到\(able+1\)这一段区间都是可以的。
  • 初始化第二颗树,\(sum\)值初始设为1,对于每个位置,如果他有前驱,那他与他前驱中这段的颜色不能计入答案,将其全部设为0,统计\(i\)\(able+1\)的值即可。
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
typedef int sign;
typedef long long ll;
#define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
#define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
const int N=3e5+5;
bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;}
bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;}
template<typename T>inline T read()
{
    T f=1,ans=0;
    char ch=getchar();
    while(!isdigit(ch)&&ch!='-')ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
    return ans*f;
}
template<typename T>inline void write(T x,char y)
{
    if(x==0)
    {
        putchar('0');putchar(y);
        return;
    }
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    static char wr[20];
    int top=0;
    for(;x;x/=10)wr[++top]=x%10+'0';
    while(top)putchar(wr[top--]);
    putchar(y);
}
void file()
{
    #ifndef ONLINE_JUDGE
        freopen("4056.in","r",stdin);
        freopen("4056.out","w",stdout);
    #endif
}
#define lson h<<1,l,mid
#define rson h<<1|1,mid+1,r
namespace T1
{
    int maxn[N<<2];
    void build(int h,int l,int r)
    {
        maxn[h]=0;
        if(l==r)return;
        int mid=(l+r)>>1;
        build(lson);build(rson);
    }
    void update(int h,int l,int r,int pos,int v)
    {
        if(l==r)
        {
            maxn[h]=v;
            return;
        }
        int mid=(l+r)>>1;
        if(pos<=mid)update(lson,pos,v);
        else update(rson,pos,v);
        maxn[h]=max(maxn[h<<1],maxn[h<<1|1]);
    }
}
namespace T2
{
    int sum[N<<2],lazy[N<<2];
    void push_down(int h)
    {
        if(!lazy[h])return;
        int ls=h<<1,rs=ls|1;
        lazy[ls]=lazy[rs]=1;
        sum[ls]=sum[rs]=0;
        lazy[h]=0;
    }
    void build(int h,int l,int r)
    {
        sum[h]=1;lazy[h]=0;
        if(l==r)return;
        int mid=(l+r)>>1;
        build(lson);build(rson);
        sum[h]=sum[h<<1]+sum[h<<1|1];
    }
    void update(int h,int l,int r,int s,int t)
    {
        if(s<=l&&r<=t)
        {
            sum[h]=0;lazy[h]=1;
            return;
        }
        push_down(h);
        int mid=(l+r)>>1;
        if(s<=mid)update(lson,s,t);
        if(mid<t)update(rson,s,t);
        sum[h]=sum[h<<1]+sum[h<<1|1];
    }
    int query(int h,int l,int r,int s,int t)
    {
        if(s<=l&&r<=t)return sum[h];
        push_down(h);
        int res=0,mid=(l+r)>>1;
        if(s<=mid)res=query(lson,s,t);
        if(mid<t)res+=query(rson,s,t);
        sum[h]=sum[h<<1]+sum[h<<1|1];
        return res;
    }
}
ll ans;
int n,m,a[N];
int pos[N],pre[N],able[N];
void input()
{
    n=read<int>();
    For(i,1,n)
    {
        a[i]=read<int>();cmax(m,a[i]);
        pre[i]=pos[a[i]];pos[a[i]]=i;
    }
}
void init()
{
    m=0;ans=0;
    memset(pos,0,sizeof pos);
    memset(able,0,sizeof able);
    memset(pre,0,sizeof pre);
}
void work()
{
    T1::build(1,1,m);
    T2::build(1,1,n);
    Fordown(i,n,1)
    {
        if(i<n)T1::update(1,1,m,a[i+1],pre[i+1]);
        able[i]=T1::maxn[1];
    }
    For(i,1,n)
    {
        if(pre[i])T2::update(1,1,n,pre[i]+1,i);
        if(able[i]+1<=i)ans+=T2::query(1,1,n,able[i]+1,i);
    }
    write(ans,'\n');
}
int main()
{
    file();
    int T=read<int>();
    while(T--)
    {
        init();
        input();
        work();
    }
    return 0;
}
posted @ 2018-01-24 10:25  dyx_diversion  阅读(280)  评论(0编辑  收藏  举报