【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 ...
随机推荐
- LDD快速参考
第二章 快速参考 本节中出现的条目会以它们在文中出现的顺序列出: insmod modprobe rmmod 用来装载模块到正运行的内核和移除模块的用户空间工具: #include <linux ...
- 用闭包解决 js 循环中函数变量暂存问题
需求:有一个数组,根据数组的值渲染对应的数字div,单击对应的div 在控制台打印对应的数字.如点击1,控制台打印1. 问题: 不管点击哪个值 打出来都是4 代码如下 <!DOCTYPE htm ...
- python生成接口自动化测试报告模版
1:准备html模版 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> &l ...
- Toposort(拓扑排序)dfs递归模板
最近刷了几题拓扑排序的题,记录一下拓扑排序 在有向图中,并且按照一定的规则(题目所给的规则)排序.如果图中出现了有向环的话就无法排序了. int gap[maxn][maxn];//记录下有向边 in ...
- linux从head.s到start_kernelstart_kernel之---内核重定位后分析
参考: https://biscuitos.github.io/blog/ARM-BOOT/ zImage 重定位之后实践 zImage 重定位之后,ARM 将 pc 指针指向了重定位 zImage ...
- 测开之路四十七:Django之请求静态资源与模板
框架必要的配置 import sysfrom django.conf.urls import urlfrom django.conf import settingsfrom django.http i ...
- SQLServer2008不允许保存更改
sql server 2008在更改表结构的时候提示 “不允许保存更改,您所做的更改要求删除并重新创建以下表” 解决方案: 1.一般情况下:工具--选项--Designers--表设计器和数据库设计器 ...
- 如何用javascript中的canvas让图片自己旋转
最近在写一个游戏,想让一个人物随着鼠标在原地旋转 在网上找了找,大都是用css写的,但是我为了长远的利益着想选择使用javascript代码中的canvas来解决绘图问题 其中重要的两个方法: con ...
- HDU多校训练第一场 1012 Sequence
题目链接:acm.hdu.edu.cn/showproblem.php?pid=6589 题意:给出一个长度为n的数组,有m次操作,操作有3种1,2,3,问操作m次后的数组,输出i*a[i]的异或和 ...
- js 模拟window.open 打开新窗口
为什么要去模拟window.open() 打开一个 新的窗口呢,因为有些浏览器默认会拦截 window.open, 当需要函数中打开新窗口时,接可以使用a标签去模拟打开. /** * a模拟windo ...