【BZOJ4095&&Gym100624D】:Non-boring sequences【线段树】

题目:

2012-2013 ACM-ICPC Central Europe Regional Contest :D

题意:

给定一个数组是"non-boring",当且仅当这个数组的每一个子区间都至少有一个唯一出现的数,否则"boring"

分析:

看到启发式分治偶然看到这道题,发现可以线段树解决;又是所有子区间,套路的枚举一下左端点L,怎么判断【L,R】(L<R<=n)都符合条件呢?还是套路的算每个数的贡献,如果一个数x第一次出现的位置是xL,第二次出现的位置是xR,那么x贡献[xL,xR-1]这段区间,那就sum[xL......xR] += 1;如果有一个位置sum[x] 等于0,显然[L,x]这个子区间是不合法的;移动左端点时,清除它的影响,同时它的下一个位置开始产生影响,对于每个L,判断【L,n】最小值是否等于0即可

代码:

#include <bits/stdc++.h>

using namespace std;
const int maxn = 2e5+25;
int T,n,a[maxn],pos[maxn],sum[maxn];
map<int,int> mp;
int MIN[maxn<<2],lazy[maxn<<2];
void BuildTree(int l,int r,int x){
    lazy[x] = 0;
    if(l == r){
        MIN[x] = sum[l];
        return ;  
    }
    int mid = (l+r) >> 1;
    BuildTree(l,mid,x<<1);
    BuildTree(mid+1,r,x<<1|1);
    MIN[x] = min(MIN[x<<1],MIN[x<<1|1]);
}
inline void pushdown(int x){
    MIN[x<<1] += lazy[x];
    MIN[x<<1|1] += lazy[x];
    lazy[x<<1] += lazy[x];
    lazy[x<<1|1] += lazy[x];
    lazy[x] = 0;
}
void UpdataTree(int l,int r,int L,int R,int x,int val){
    if(l > R || r < L) return ;
    if(l >= L && r <= R){
        MIN[x] += val;
        lazy[x] += val;
        return ;
    }
    if(lazy[x]) pushdown(x);
    int mid = (l+r) >> 1;
    UpdataTree(l,mid,L,R,x<<1,val);
    UpdataTree(mid+1,r,L,R,x<<1|1,val);
    MIN[x] = min(MIN[x<<1],MIN[x<<1|1]);
}
void QueryTree(int l,int r,int L,int R,int x,int &val){
    if(val <= 0) return ;
    if(l > R || r < L) return;
    if(l >= L && r <= R){
        val = min(val,MIN[x]);
        return ;
    }
    if(lazy[x]) pushdown(x);
    int mid = (l+r) >> 1;
    QueryTree(l,mid,L,R,x<<1,val);
    QueryTree(mid+1,r,L,R,x<<1|1,val);
}
bool solve(){
    for(int i = 1;i < n; ++i){
        int val = 1e8; QueryTree(1,n,i,n,1,val);
        if(val <= 0) return false;
        UpdataTree(1,n,i+1,pos[i]-1,1,-1);
        if(pos[i] <= n) UpdataTree(1,n,pos[i],pos[pos[i]]-1,1,1);
    }
    return true;
}
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n); mp.clear() ;
        for(int i = 1;i <= n; ++i) scanf("%d",a+i);
        for(int i = n;i > 0; --i){
            if(mp.count(a[i])) pos[i] = mp[a[i]];
            else pos[i] = n+1;
            mp[a[i]] = i;
        }
        mp.clear();
        for(int i = 1;i <= n; ++i){
            if(mp.count(a[i])){
                if(mp[a[i]]==1) sum[i] = sum[i-1] - 1;
                else sum[i] = sum[i-1];
            }
            else sum[i] = sum[i-1] + 1;
            mp[a[i]]++;
        }
        BuildTree(1,n,1);
        if(solve()) puts("non-boring");
        else puts("boring");
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值