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

hdu6602---线段树

时间:2019-09-11 00:01:04      阅读:105      评论:0      收藏:0      [点我收藏+]

标签:else   back   change   子串   sub   array   数列   hdu   数字   

Longest Subarray

题意:一个数列,每个元素大小都在1到C之间,求一个最长的子串,满足在这个子串中1到C之间的每个数字要么出现0次,要么出现至少K次。

题解:\(i\)从1到n枚举右端点,维护一个\(tree[j]\)表示在\(i\)为右端点时以\(j\)为左端点可行的个数(这里的可行是指对于1到C之间的某一个数是否可行,即\(j\)\(i\)之间\(X\)的个数是否满足题意,\(X\epsilon(1,C)\))。那么对于固定的\(i\)显然当\(tree[j]==C\)\([j,i]\)是一个可行区间,找出最小的\(j\)即可. 上述操作在线段树上维护.

#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,c,k,a[100005];
int tree[maxn*4],tag[maxn*4];
inline int ls(int x){
    return x<<1;
}
inline int rs(int x){
    return x<<1|1;
}
void change(int root,int del){
    tree[root]+=del;
    tag[root]+=del;
}
void pushdown(int root,int l,int r){
    if(!tag[root]) return;
    int mid=(l+r)>>1;
    change(ls(root),tag[root]);
    change(rs(root),tag[root]);
    tag[root]=0;
}
void update(int root,int l,int r,int il,int ir,int del){
    if(r<il||l>ir) return;
    if(l>=il&&r<=ir) {
        tree[root] += del;
        tag[root] += del;
        return;
    }
    pushdown(root,l,r);
    int mid=(l+r)>>1;
    update(ls(root),l,mid,il,ir,del);
    update(rs(root),mid+1,r,il,ir,del);
    tree[root]=max(tree[ls(root)],tree[rs(root)]);
}
int ask(int root,int l,int r,int il,int ir){
    if(r<il||l>ir) return -1;
    if(tree[root]<c) return -1;
    if(l==r) return l;
    pushdown(root,l,r);
    int mid=(l+r)>>1;
    int tmp=ask(ls(root),l,mid,il,ir);
    if(tmp>0) return tmp;
    return ask(rs(root),mid+1,r,il,ir);
}
vector<int> pos[maxn];
int main(){
    while(~scanf("%d%d%d",&n,&c,&k)) {
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=c;i++) {
            pos[i].clear();
        }
        if(k==1){
            printf("%d\n",n); continue;
        }
        int nn=n*4;
        for(int i=1;i<=nn;i++) tree[i]=0,tag[i]=0;
        int ans=0;
        for(int i=1;i<=n;i++){
            pos[a[i]].push_back(i);
            update(1,1,n,i,i,c-1);
            int siz=pos[a[i]].size();
            if(siz>=1){
                int l=siz-2,r=siz-1;
                if(l<0) l=1;
                else l=pos[a[i]][l]+1;
                r=pos[a[i]][r]-1;
                if(l<=r) update(1,1,n,l,r,-1);
            }
            if(siz>=k){
                int l=siz-k-1,r=siz-k;
                if(l<0) l=1;
                else l=pos[a[i]][l]+1;
                r=pos[a[i]][r];
                update(1,1,n,l,r,1);
            }
            int tmp=ask(1,1,n,1,i);
            if(tmp>0) ans=max(ans,i-tmp+1);
        }
        printf("%d\n",ans);
    }
    return 0;
}

hdu6602---线段树

标签:else   back   change   子串   sub   array   数列   hdu   数字   

原文地址:https://www.cnblogs.com/vege-chicken-rainstar/p/11503606.html

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