题意:给你一个序列,求满足要求的子序列个数,其中要求为:

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【权值线段树+双向单调队列】的更多相关文章

  1. 【树状数组套权值线段树】bzoj1901 Zju2112 Dynamic Rankings

    谁再管这玩意叫树状数组套主席树我跟谁急 明明就是树状数组的每个结点维护一棵动态开结点的权值线段树而已 好吧,其实只有一个指针,指向该结点的权值线段树的当前结点 每次查询之前,要让指针指向根结点 不同结 ...

  2. 【BZOJ-2892&1171】强袭作战&大sz的游戏 权值线段树+单调队列+标记永久化+DP

    2892: 强袭作战 Time Limit: 50 Sec  Memory Limit: 512 MBSubmit: 45  Solved: 30[Submit][Status][Discuss] D ...

  3. BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)

    题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...

  4. 动态求区间K大值(权值线段树)

    我们知道我们可以通过主席树来维护静态区间第K大值.我们又知道主席树满足可加性,所以我们可以用树状数组来维护主席树,树状数组的每一个节点都可以开一颗主席树,然后一起做. 我们注意到树状数组的每一棵树都和 ...

  5. 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题

    “队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄>     线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...

  6. 【BZOJ3685】【zkw权值线段树】普通van Emde Boas树

    原题传送门 因为马上要开始搞树套树了,所以学了一波权值线段树...毕竟是会点zkw线段树的,所以zkw线段树大法好! 解题思路: 介绍一下权值线段树吧,其实感觉就是线段树的本义,就是你用线段树维护了数 ...

  7. BZOJ_2161_布娃娃_权值线段树

    BZOJ_2161_布娃娃_权值线段树 Description 小时候的雨荨非常听话,是父母眼中的好孩子.在学校是老师的左右手,同学的好榜样.后来她成为艾利斯顿第二 代考神,这和小时候培养的良好素质是 ...

  8. BZOJ_3685_普通van Emde Boas树_权值线段树

    BZOJ_3685_普通van Emde Boas树_权值线段树 Description 设计数据结构支持: 1 x  若x不存在,插入x 2 x  若x存在,删除x 3    输出当前最小值,若不存 ...

  9. B20J_2733_[HNOI2012]永无乡_权值线段树合并

    B20J_2733_[HNOI2012]永无乡_权值线段树合并 Description:n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示.某些 ...

随机推荐

  1. docker 部署ftp

    1.搜索ftp镜像 docker search vsftpd 2.拉取ftp镜像 docker pull fauria/vsftpd 3.启动ftpdocker docker run -d -v /h ...

  2. python读写excle

    我们可以通过python的一些模块进行excle中用例的读取,或者导出数据到excle 目录 1.安装模块 2.读excle 3.写excle 1.安装模块 python中有第三方模块可以进行excl ...

  3. java Json 技术记录

    1.Json-lib json-lib最开始的也是应用最广泛的json解析工具,json-lib 不好的地方确实是依赖于很多第三方包,包括commons-beanutils.jar,commons-c ...

  4. CSAPP:局部性原理

    一个编写良好的计算机程序常常具有良好的局部性(locality).局部性通常有两种不同的形式:时间局部性(temporal locality)和空间局部性(spatial locality).在一个具 ...

  5. 获取EasyUI日期输入框的值

    var date = $('#PurDate').datebox('getValue');

  6. sqlserver关于时间的一些语句

    /* 去掉时间的时分秒 */ CONVERT(CHAR(10),operate_time,120) /* 所有的天数增加一天 */ DATEADD(day,1,t.operate_time) /* 返 ...

  7. ES6---new Promise()讲解,Promise对象是用来干嘛的?

    ES6---new Promise()讲解,Promise对象是用来干嘛的? :https://blog.csdn.net/Wbiokr/article/details/79490390

  8. Spark链接hive时 “HikariCP” 问题

    IDE本地调试和spark-shell调试报错: Caused by: org.datanucleus.exceptions.NucleusUserException: The connection ...

  9. CGAffineTransform 图像处理类

    CGAffineTransform 介绍 概述 CGAffineTransform是一个用于处理形变的类,其可以改变控件的平移.缩放.旋转等,其坐标系统采用的是二维坐标系,即向右为x轴正方向,向下为y ...

  10. Python网络编程:Linux epoll

    原文地址:http://scotdoyle.com/python-epoll-howto.html 介绍 Python已于2.6版本添加访问Linux epoll库的API.这篇教程使用Python ...