【HDU6602】Longest Subarray【线段树+分治】
题目大意:给出一串序列,询问最长的合法子串为多长,其中合法子串必须满足子串中[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【线段树+分治】的更多相关文章
- 2019杭电多校第二场hdu6602 Longest Subarray(线段树)
Longest Subarray 题目传送门 解题思路 本题求一个最大的子区间,满足区间内的数字要么出现次数大于等于k次,要么没出现过.给定区间内的数字范围是1~c. 如果r为右边界,对于一种数字x, ...
- [2019杭电多校第二场][hdu6602]Longest Subarray(线段树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6602 题目大意为求最长的区间,满足C种数字在区间内要么不出现,要么出现的次数都不小于K. 大致的分析一 ...
- 2019杭电多校二 L. Longest Subarray (线段树)
大意: 给定序列$a$, 元素范围$[1,C]$, 求一个最长子序列, 满足每个元素要么不出现, 要么出现次数$\le K$. 枚举右端点, 考虑左端点合法的位置. 显然一定是$C$种颜色合法位置的交 ...
- HDU 6602 Longest Subarray (线段树)
题意: 1e5的数组,c(1e5)种数字求最长的子串,使得其中每个出现的数字出现的次数为0次或者大于k次 思路: 枚举右端点i,维护当前右端点时,每个左端点的可行元素数量,当且仅当可行元素为c时更新答 ...
- HDU6602 Longest Subarray hdu多校第二场 线段树
HDU6602 Longest Subarray 线段树 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6602 题意: 给你一段区间,让你求最长的区间使 ...
- loj#2312. 「HAOI2017」八纵八横(线性基 线段树分治)
题意 题目链接 Sol 线性基+线段树分治板子题.. 调起来有点自闭.. #include<bits/stdc++.h> #define fi first #define se secon ...
- BZOJ.4184.shallot(线段树分治 线性基)
BZOJ 裸的线段树分治+线性基,就是跑的巨慢_(:з」∠)_ . 不知道他们都写的什么=-= //41652kb 11920ms #include <map> #include < ...
- BZOJ.4137.[FJOI2015]火星商店问题(线段树分治 可持久化Trie)
BZOJ 洛谷 一直觉得自己非常zz呢.现在看来是真的=-= 注意题意描述有点问题,可以看BZOJ/洛谷讨论. 每个询问有两个限制区间,一是时间限制\([t-d+1,t]\),二是物品限制\([L,R ...
- 洛谷.3733.[HAOI2017]八纵八横(线性基 线段树分治 bitset)
LOJ 洛谷 最基本的思路同BZOJ2115 Xor,将图中所有环的异或和插入线性基,求一下线性基中数的异或最大值. 用bitset优化一下,暴力的复杂度是\(O(\frac{qmL^2}{w})\) ...
- bzoj4025二分图(线段树分治 并查集)
/* 思维难度几乎没有, 就是线段树分治check二分图 判断是否为二分图可以通过维护lct看看是否链接出奇环 然后发现不用lct, 并查集维护奇偶性即可 但是复杂度明明一样哈 */ #include ...
随机推荐
- temp = yield i 这句话的意思?
def test(): i = 0 while i < 5: temp = yield i # print(temp) i+=1 t = test() print(t.__next__()) p ...
- git查看切换分支
Git一般有很多分支,我们clone到本地的时候一般都是master分支,那么如何切换到其他分支呢?主要命令如下: 1. 查看远程分支 $ git branch -a 我在mxnet根目录下运行以上命 ...
- flutte页面布局四
AspectRatio 组件 AspectRatio 的作用是根据设置调整子元素 child 的宽高比. AspectRatio 首先会在布局限制条件允许的范围内尽可能的扩展,widget 的高度是由 ...
- 四两拨千斤,ARM是如何运作、靠什么赚钱的
在智能手机.平板大行其道的今天,ARM这个名字我们几乎每天都要见到或者听到几次,作为编辑的我更是如此,每天涉及到的新闻总是或多或少跟ARM扯上关系,它还与Intel.AMD.NVIDA等公司有说不清道 ...
- MySQL 添加用户、删除用户与授权
mysql -uroot -proot MySQL5.7 mysql.user表没有password字段改 authentication_string: 一. 创建用户: 命令:CREATE USER ...
- Note1
1.关于数据库主从备份与读写分离 主服务器数据库的每次操作都会记录在二进制日志文件mysql-bin.xxx中.从服务器的I/O线程使用专用帐号登陆到主服务器中读取该二进制文件,并将文件内容写入到自己 ...
- Html5 学习笔记 【PC固定布局】 实战4 footer 区域
最终效果图: Html代码: <!DOCTYPE html> <html lang="zh-cn"> <head> <meta chars ...
- 百度分布式配置管理平台-Disconf
Disconf介绍 全称:Distributed Configuration Management Platform,即分布式配置管理平台. Disconf专注于各种分布式系统配置管理的通用组件和通用 ...
- leetcode.排序.347前k个高频元素-Java
1. 具体题目 给定一个非空的整数数组,返回其中出现频率前 k 高的元素. 示例 1: 输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2] 示例 2: 输入: nums ...
- subprocess 模块 与 re 模块
sub :子 process:进程 用法: import subprocess while True: cmd_str = inport('请输入终端命令:') obj = subprocrss.Po ...