题目大意:给出一串序列,询问最长的合法子串为多长,其中合法子串必须满足子串中[1,C]的数量大于等于K或者为0

题解:

定义右端点为包含某一点所需要的最小区间的右端点

那么初始化时就可以O(n)求出每个点的右端点

定义最小包含区间为某个点到其右端点的区间

定义不同的区间为当两个最小包含区间的最左边元素不同时两个区间为不同

那么不难想到,一个合法的子串,当且仅当所有最靠左边的不同的区间都被包含在子串内,此时子串合法

因此,不难想到当出现一个不合法区间时,将这个不合法区间的左端点作为分割点,分为左右两边进行递归操作

于是有了一个分治的做法,一开始询问子串[1,n]是否合法,若合法,则可能为答案,若不合法,则找到所有不合法的左端点,将其作为分割点分治下去

找不合法的左端点是复杂度瓶颈,我们考虑优化它

维护一个线段树,线段树维护最大的右端点,以及提供这个右端点的点在哪

那么不难想到每次只需要询问线段树[l,r]得到右端点看是否右端点大于r,大于则不合法,线段树返回的另一个值就是不合法点,将其作为分割点进行分治

考虑到所有相同的颜色我只需要最左边的还有用的,于是一开始时只需要把每个颜色最左边的区间加入线段树,分治时严格从左到右,删点时删除一个点的同时将删除点的颜色的下一个区间加入线段树,这样就能保证答案没有遗漏或者出错

因为每个点只会被加入一次和删除一次,所以时间复杂度为O(nlogn),可以通过此题

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#define INF 1000000007
using namespace std;
int n,c,k,tans;
int a[],nxt[],hd[];
int minsb[];
struct node
{
int p,minr;
}dat[*]; void pushup(int pos)
{
if(dat[pos<<].minr>=dat[pos<<|].minr)dat[pos]=dat[pos<<];
else dat[pos]=dat[pos<<|];
}
void change(int l,int r,int p,int v,int pos)
{
//printf("%d %d %d\n",l,r,p);
if(l==r && l==p)
{
dat[pos]=(node){p,v};
return;
}
int mid=l+r>>;
if(p<=mid)change(l,mid,p,v,pos<<);
else change(mid+,r,p,v,pos<<|);
pushup(pos);
}
node ask(int l,int r,int al,int ar,int pos)
{
if(l==al && r==ar)return dat[pos];
int mid=l+r>>;
node t1,t2;
if(ar<=mid)return ask(l,mid,al,ar,pos<<);
if(al>mid)return ask(mid+,r,al,ar,pos<<|);
t1=ask(l,mid,al,mid,pos<<);
t2=ask(mid+,r,mid+,ar,pos<<|);
if(t1.minr>=t2.minr)return t1;
else return t2;
}
void work(int l,int r)
{
//printf("%d %d\n",l,r);
if(l>r)return;
node td=ask(,n,l,r,);
//printf(" %d %d\n",td.p,td.minr);
if(l==r)
{
if(td.minr<=r)tans=max(tans,);
change(,n,l,,);
if(nxt[l])change(,n,nxt[l],minsb[nxt[l]],);
return;
}
if(td.minr>r)
{
work(l,td.p-);
change(,n,td.p,,);
if(nxt[td.p])change(,n,nxt[td.p],minsb[nxt[td.p]],);
work(td.p+,r);
}
else
{
tans=max(tans,r-l+);
for(int i=l;i<=r;i++)
{
//printf("*%d* %d\n",i,nxt[i]);
change(,n,i,,);
//printf("==-=-=-=-=-=-=\n");
if(nxt[i])change(,n,nxt[i],minsb[nxt[i]],);
}
return;
}
}
void init()
{
memset(a,,sizeof(a));
memset(nxt,,sizeof(nxt));
memset(hd,,sizeof(hd));
memset(minsb,,sizeof(minsb));
for(int i=;i<=n;i++)change(,n,i,,);
tans=;
}
int main()
{
while(scanf("%d%d%d",&n,&c,&k)!=EOF)
{
init();
for(int i=;i<=n;i++)scanf("%d",&a[i]);
for(int i=n;i>;i--)
{
nxt[i]=hd[a[i]];
hd[a[i]]=i;
}
for(int i=;i<=c;i++)
{
int t=hd[i],l=,j;
if(!t)continue;
j=t;
while(l<k && j)
{
j=nxt[j];
if(j)l++;
}
if((!j) || l<k)
{
while(t){minsb[t]=INF;t=nxt[t];}
}
else
{
while(t && j){minsb[t]=j;j=nxt[j];t=nxt[t];}
while(t){minsb[t]=INF;t=nxt[t];}
}
}
for(int i=;i<=c;i++)if(hd[i])change(,n,hd[i],minsb[hd[i]],);
work(,n);
printf("%d\n",tans);
//for(int i=1;i<=n;i++)printf("%d ",minsb[i]);
}
return ;
}

心得:考场上很快就想到了区间的做法,但是最后维护线段树时只放最左边的想法一直没有突破导致浪费了一点时间,还需要更加努力啊

【HDU6602】Longest Subarray【线段树+分治】的更多相关文章

  1. 2019杭电多校第二场hdu6602 Longest Subarray(线段树)

    Longest Subarray 题目传送门 解题思路 本题求一个最大的子区间,满足区间内的数字要么出现次数大于等于k次,要么没出现过.给定区间内的数字范围是1~c. 如果r为右边界,对于一种数字x, ...

  2. [2019杭电多校第二场][hdu6602]Longest Subarray(线段树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6602 题目大意为求最长的区间,满足C种数字在区间内要么不出现,要么出现的次数都不小于K. 大致的分析一 ...

  3. 2019杭电多校二 L. Longest Subarray (线段树)

    大意: 给定序列$a$, 元素范围$[1,C]$, 求一个最长子序列, 满足每个元素要么不出现, 要么出现次数$\le K$. 枚举右端点, 考虑左端点合法的位置. 显然一定是$C$种颜色合法位置的交 ...

  4. HDU 6602 Longest Subarray (线段树)

    题意: 1e5的数组,c(1e5)种数字求最长的子串,使得其中每个出现的数字出现的次数为0次或者大于k次 思路: 枚举右端点i,维护当前右端点时,每个左端点的可行元素数量,当且仅当可行元素为c时更新答 ...

  5. HDU6602 Longest Subarray hdu多校第二场 线段树

    HDU6602 Longest Subarray 线段树 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6602 题意: 给你一段区间,让你求最长的区间使 ...

  6. loj#2312. 「HAOI2017」八纵八横(线性基 线段树分治)

    题意 题目链接 Sol 线性基+线段树分治板子题.. 调起来有点自闭.. #include<bits/stdc++.h> #define fi first #define se secon ...

  7. BZOJ.4184.shallot(线段树分治 线性基)

    BZOJ 裸的线段树分治+线性基,就是跑的巨慢_(:з」∠)_ . 不知道他们都写的什么=-= //41652kb 11920ms #include <map> #include < ...

  8. BZOJ.4137.[FJOI2015]火星商店问题(线段树分治 可持久化Trie)

    BZOJ 洛谷 一直觉得自己非常zz呢.现在看来是真的=-= 注意题意描述有点问题,可以看BZOJ/洛谷讨论. 每个询问有两个限制区间,一是时间限制\([t-d+1,t]\),二是物品限制\([L,R ...

  9. 洛谷.3733.[HAOI2017]八纵八横(线性基 线段树分治 bitset)

    LOJ 洛谷 最基本的思路同BZOJ2115 Xor,将图中所有环的异或和插入线性基,求一下线性基中数的异或最大值. 用bitset优化一下,暴力的复杂度是\(O(\frac{qmL^2}{w})\) ...

  10. bzoj4025二分图(线段树分治 并查集)

    /* 思维难度几乎没有, 就是线段树分治check二分图 判断是否为二分图可以通过维护lct看看是否链接出奇环 然后发现不用lct, 并查集维护奇偶性即可 但是复杂度明明一样哈 */ #include ...

随机推荐

  1. 教你建立SQL数据库的表分区

    1)新建一个数据库 2)添加几个文件组 3)回到“常规”选项卡,添加数据库文件 看到用红色框框起来的地方没?上一步中建立的文件组在这里就用上了.再看后面的路径,我把每一个文件都单独放在不同的磁盘上,而 ...

  2. PHP curl_multi_exec函数

    curl_multi_exec — 运行当前 cURL 句柄的子连接 说明 int curl_multi_exec ( resource $mh , int &$still_running ) ...

  3. LVS负载均衡中arp_ignore和arp_annonuce参数配置

    先简单的介绍下关于LVS负载均衡 LVS(Linux  Virtual Server)Linux服务器集群系统 针对高可伸缩,高可用服务的需求,给予IP层和内容请求分发的负载均衡调度解决方法,并在Li ...

  4. git分支merger

  5. 登录成功后如何利用cookie保持登录状态

    Cookie是一种服务器发送给浏览器的一组数据,用于浏览器跟踪用户,并访问服务器时保持登录状态等功能. 通常用户登录的时候,服务器根据用户名和密码在服务器数据库中校验该用户是否正确,校验正确后则可以根 ...

  6. three dots in git

    What are the differences between double-dot “..” and triple-dot “…” in Git commit ranges? Using Comm ...

  7. Red Gate .NET Reflector

    Debug and decompile inside Visual Studio (VSPro edition) Use the Visual Studio debugger Use your reg ...

  8. idhttp提交post

    var Param:TStringList; RStream:TMemoryStream;begin Param:=TStringList.Create; RStream:=TMemoryStream ...

  9. Python笔记(八)_内部函数与闭包

    内部函数 在函数内部定义另一个函数,也就是函数的嵌套 在外部函数的作用域内,外部函数可以随意调用内部函数 由于内部函数的整个定义过程都在外部函数中,所以出了外部函数就无法再被调用了 def outsi ...

  10. 箫声远(本人)的小站(为展示作品、简历,基于github pages)

    箫声远的个人前端小站在线地址