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

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. CSS-父元素宽度自适应子元素宽度之和

    最近碰见这样一个需求,要让图片横向排列设置 x 方向的滚动条滚动查看,原本当直接创建一个 IFC(inline,float 什么的)就解决了,搞了半天发现搞不定(IFC 也是不能父元素宽度自适应子元素 ...

  2. IntelliJ IDEA中创建xml文件

      1.file—setting,左上角输入template, 2.在左侧栏找到File And Code Templates 3.中间选中Files 4.点击+号,添加模板 5.输入模板名字:Nam ...

  3. SqlSession 内部运行

    <深入浅出MyBatis技术原理与实战>p150页 SqlSession内部运行图 四大对象在流程中的操作. 1.准备sql.StatementHandler 的prepare方法进行sq ...

  4. mariadb(一)基础

    一.数据库介绍 1.什么是数据库? 简单的说,数据库就是一个存放数据的仓库,这个仓库是按照一定的数据结构(数据结构是指数据的组织形式或数据之间的联系)来组织,存储的,我们可以通过数据库提供的多种方法来 ...

  5. tomcat启动控制台报Exception in thread ''main".......“Could not find the main class:.....Bootstrap”问题

    startup.bat文件打开最后end下一行加pause调试,重新启动tomcat,发现配置没问题,但是依然报错,发现是jdk版本问题,jdk1.6无法与tomcat8适配,重新装个1.7版本的jd ...

  6. Drone 持续集成实践 - 基于 Gogs,以 Golang 为例

    Drone 官方示例 - Example Go project 用 Docker 部署 Go 服务器 Golang 官方示例 - outyet 一个生产环境的例子 用 rsync 复制文件的方式进行部 ...

  7. PHP批量生成底部带编号二维码(二维码生成+文字生成图片+图片拼接合并)

    PHP批量生成带底部编号二维码(二维码生成+文字生成图片+图片拼接合并) 需求: 输入编号如 : cb05-0000001  至 cb05-0000500 批量生成 以编号为名称的下图二维码,然后压缩 ...

  8. Bootstrap 学习笔记5 进度条媒体对象和well组件

    代码: <ul class="media-list"> <li class="media"> <div class="m ...

  9. 2019/10/26 TZOJ

    1001 Flooded Island http://www.tzcoder.cn/acmhome/problemdetail.do?&method=showdetail&id=452 ...

  10. 【python】 判断纯ascii串

    参考:http://stackoverflow.com/questions/3636928/test-if-a-python-string-is-printable print all(ord(c)& ...