【HDU6701】Make Rounddog Happy【权值线段树+双向单调队列】

题意:给你一个序列,求满足要求的子序列个数,其中要求为:
1、子序列的max-子序列长度len<=k
2、子序列中不出现重复的数字
题解:首先看到子序列max,很容易想到枚举最大值然后分治,这个做法有人通过,但是我并没想到如何做
子序列max还有一个思路是单调队列,这里我们通过单调队列进行解题
首先对于给出的限制条件式子max-(r-l+1)<=k,我们进行移项,可得max+l<=k+r+1,此时我们将l和r分离至不等式两边
容易看出我们可以枚举右端点,然后维护一个权值线段树,每次只需要查询1~k+r+1区间的sum就可以了
以max+l作为权值建线段树
那么容易想到用单调队列进行维护max,每次更新单调队列的时候相当于在权值线段树上的一个区间进行+1/-1操作
单调队列维护:值,位置,这个值的左端点
维护单调队列时为了满足子序列不出现重复数字,于是考虑双向单调队列
新枚举右端点时,单调队列从右往左退栈,直到第一个不小于右端点数字的位置
然后考虑此时的最左边能到哪里
考虑记下每一个位置的前驱位置,即前一个相同数字在哪
容易想到维护一个最大值表示当前的最左端点在哪,每新枚举一个右端点,那么将last[i]+1和当前的左端点取个max,即为新的左端点,显然这样是当前右端点下最大的满足条件的左端点
于是单调队列从左往右退栈,直到第一个下标大于等于左端点的位置,然后再更新单调队列里维护的左端点
至此则可以在nlogn的时间内求出答案
时间复杂度O(nlogn)
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#define ll long long
using namespace std;
int T;
int n,k;
int a[],last[],hd[];
int lh[],mx[],mxi[],ln,rn;
ll ans;
class Segtree
{
public:
ll v[*],flv[*];
bool fl[*]; void init()
{
memset(v,,sizeof(v));
memset(fl,,sizeof(fl));
memset(flv,,sizeof(flv));
}
void pushdown(int l,int r,int pos)
{
if(fl[pos])
{
int mid=l+r>>;
v[pos<<]+=flv[pos]*(mid-l+);
v[pos<<|]+=flv[pos]*(r-mid);
flv[pos<<]+=flv[pos];
flv[pos<<|]+=flv[pos];
fl[pos<<]=fl[pos<<|]=;
fl[pos]=;flv[pos]=;
}
}
void pushup(int pos)
{
v[pos]=v[pos<<]+v[pos<<|];
}
void change(int l,int r,int al,int ar,ll tv,int pos)
{
if(l==al && r==ar)
{
v[pos]+=tv*(ar-al+);
fl[pos]=;
flv[pos]+=tv;
return;
}
pushdown(l,r,pos);
int mid=l+r>>;
if(ar<=mid)change(l,mid,al,ar,tv,pos<<);
if(al>mid)change(mid+,r,al,ar,tv,pos<<|);
if(al<=mid && ar>mid)
{
change(l,mid,al,mid,tv,pos<<);
change(mid+,r,mid+,ar,tv,pos<<|);
}
pushup(pos);
}
ll ask(int l,int r,int al,int ar,int pos)
{
if(l==al && r==ar)return v[pos];
int mid=l+r>>;
pushdown(l,r,pos);
if(ar<=mid)return ask(l,mid,al,ar,pos<<);
if(al>mid)return ask(mid+,r,al,ar,pos<<|);
if(al<=mid && ar>mid)return ask(l,mid,al,mid,pos<<)+ask(mid+,r,mid+,ar,pos<<|);
}
}segtree;
int main()
{
scanf("%d",&T);
while(T--)
{
segtree.init();
ans=;
memset(hd,,sizeof(hd));
memset(last,,sizeof(last));
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
last[i]=hd[a[i]];
hd[a[i]]=i;
}
ln=;rn=;int tl,tl2=;
for(int i=;i<=n;i++)
{
tl=i;tl2=max(tl2,last[i]+);
while(ln<=rn && mx[rn]<a[i])
{
tl=min(tl,lh[rn]);
segtree.change(,n*,mx[rn]+lh[rn],mx[rn]+mxi[rn],-,);
rn--;
}
segtree.change(,n*,a[i]+tl,a[i]+i,,);
rn++;
lh[rn]=tl;mx[rn]=a[i];mxi[rn]=i;
while(ln<=rn && mxi[ln]<tl2)
{
segtree.change(,n*,mx[ln]+lh[ln],mx[ln]+mxi[ln],-,);
ln++;
}
if(ln<=rn && lh[ln]<tl2)
{
segtree.change(,n*,mx[ln]+lh[ln],mx[ln]+tl2-,-,);
lh[ln]=tl2;
}
ans+=segtree.ask(,n*,,min(i+k+,n*),);
}
printf("%lld\n",ans);
}
return ;
}
心得:区间max的处理方法不仅有枚举max然后分治,还有单调队列,思维不要唯一,要多想一些
【HDU6701】Make Rounddog Happy【权值线段树+双向单调队列】的更多相关文章
- 【树状数组套权值线段树】bzoj1901 Zju2112 Dynamic Rankings
谁再管这玩意叫树状数组套主席树我跟谁急 明明就是树状数组的每个结点维护一棵动态开结点的权值线段树而已 好吧,其实只有一个指针,指向该结点的权值线段树的当前结点 每次查询之前,要让指针指向根结点 不同结 ...
- 【BZOJ-2892&1171】强袭作战&大sz的游戏 权值线段树+单调队列+标记永久化+DP
2892: 强袭作战 Time Limit: 50 Sec Memory Limit: 512 MBSubmit: 45 Solved: 30[Submit][Status][Discuss] D ...
- BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)
题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...
- 动态求区间K大值(权值线段树)
我们知道我们可以通过主席树来维护静态区间第K大值.我们又知道主席树满足可加性,所以我们可以用树状数组来维护主席树,树状数组的每一个节点都可以开一颗主席树,然后一起做. 我们注意到树状数组的每一棵树都和 ...
- 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题
“队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄> 线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...
- 【BZOJ3685】【zkw权值线段树】普通van Emde Boas树
原题传送门 因为马上要开始搞树套树了,所以学了一波权值线段树...毕竟是会点zkw线段树的,所以zkw线段树大法好! 解题思路: 介绍一下权值线段树吧,其实感觉就是线段树的本义,就是你用线段树维护了数 ...
- BZOJ_2161_布娃娃_权值线段树
BZOJ_2161_布娃娃_权值线段树 Description 小时候的雨荨非常听话,是父母眼中的好孩子.在学校是老师的左右手,同学的好榜样.后来她成为艾利斯顿第二 代考神,这和小时候培养的良好素质是 ...
- BZOJ_3685_普通van Emde Boas树_权值线段树
BZOJ_3685_普通van Emde Boas树_权值线段树 Description 设计数据结构支持: 1 x 若x不存在,插入x 2 x 若x存在,删除x 3 输出当前最小值,若不存 ...
- B20J_2733_[HNOI2012]永无乡_权值线段树合并
B20J_2733_[HNOI2012]永无乡_权值线段树合并 Description:n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示.某些 ...
随机推荐
- Centos7.6 安装
序:在“Intel 英特尔 NUC6I7KYK 迷你主机” 上 安装“Centos7.6” 一.制作U盘启动盘 参考<制作CentOS的U盘启动盘>.<制作 CentOS7的U盘系统 ...
- PADS 学习资料
PADS软件: PADS9.5_3in1.7z 链接: http://pan.baidu.com/s/1epO4Y 密码: zltl 打不开程序的博友,请看你的电脑有没有安装常用软件运行库 ...
- 测开之路六十二:接口测试平台之公共的js、html、平台入口
common.js //定义后台的host和端口var host = 'http://192.168.xxx.1:8000'; //'http://127.0.0.1:8000'; //用于发送htt ...
- Jquery.extend()和jQuery.fn.extend(object);
摘自: jquery $.fn $.fx是什么意思有什么用_jquery_脚本之家 jQuery.extend(object); 为扩展jQuery类本身.为类添加新的方法. jQuery.fn.ex ...
- 【ABAP系列】SAP ABAP模块-取整操作中CEIL和FLOOR用法
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP模块-取整操作中 ...
- C#联接序列
1. Concat() – 串联序列(有重复项) var healthFoods = new List<string> { "fruits", "veget ...
- 《JAVA设计模式》之装饰模式(Decorator)
在阎宏博士的<JAVA与模式>一书中开头是这样描述装饰(Decorator)模式的: 装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替 ...
- 记录XorDDos木马清理步骤
1.检查 查看定时任务文件发现有两个异常定时任务 [root@manage ~]# cat /etc/crontab # * * * * * user-name command to be execu ...
- [LOJ3123] CTSC2019重复
Description 给定一个⻓为 n 的字符串 s , 问有多少个⻓为 m 的字符串 t 满足: 将 t 无限重复后,可以从中截出一个⻓度为 n 且字典序比 s 小的串. m ≤ 2000 n ≤ ...
- 难倒你了吧!ArrayList 为啥要实现 RandomAccess 接口?
作者:蔡先森_caiyq https://www.jianshu.com/p/3e2a9e4c9e01 在我们的开发中,List接口是最常见不过,而且我们几乎每天都在用ArrayList或者Linke ...