题面

传送门

分析

对于每一个数a[i],找到它后面第一个大于它的数a[p],由p向i连边,最终我们就会得到一个森林,且p是i的父亲。为了方便操作,我们再增加一个虚拟节点n+1,把森林变成树。

由于序列不是递增的,不能二分。维护一个单调栈,栈顶元素最小。从n到1依次对每个 数操作,弹出栈里比它小的数。如果栈为空,说明该数是森林中的根节点,向n+1连边。否则栈顶元素就是第一个大于它的数,向它的编号连边即可。

我们发现,对于每个查询区间内的所有数,它对应着树上的某些节点,记为标记节点。如果把标记节点之间的非标记节点去掉,我们就会得到一棵新树,新树上从某个节点到根的一条路径对应着一个满足条件的序列,则最大序列长度等于新树上从叶子节点到根的最长路径。这样,我们就把问题转化为了树上的最长路径。

显然不能对每一个询问建一棵新树。我们发现新树上的路径长度就是原树上的路径经过的标记节点个数,如图(加粗的节点为标记节点)。

所以,我们建立一棵线段树,线段树的叶子节点存储原树上每个节点到根的路径上的标记节点个数,线段树维护最大值。

我们枚举每个长度为k的区间[i,i+k-1],显然从前一个区间转移到当前区间时,只会增加一个标记节点,减少一个标记节点。每增加一个标记节点i,我们就将i的子树内的所有节点的值+1,否则-1。答案即为整颗线段树的最大值

时间复杂度\(O(n\log n)\)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
#include<algorithm>
#define maxn 1000005
using namespace std;
int n,k;
int a[maxn];
struct edge{
int from;
int to;
int next;
}E[maxn<<1];
int head[maxn];
int sz=1;
void add_edge(int u,int v){
sz++;
E[sz].from=u;
E[sz].to=v;
E[sz].next=head[u];
head[u]=sz;
}
int cnt=0;
int lb[maxn],rb[maxn];
void dfs(int x,int fa){
lb[x]=++cnt;
for(int i=head[x];i;i=E[i].next){
int y=E[i].to;
if(y!=fa){
dfs(y,x);
}
}
rb[x]=cnt;
} struct node{
int l;
int r;
int v;
int mark;
}tree[maxn<<2];
void push_up(int pos){
tree[pos].v=max(tree[pos<<1].v,tree[pos<<1|1].v);
}
void build(int l,int r,int pos){
tree[pos].l=l;
tree[pos].r=r;
if(l==r){
return;
}
int mid=(l+r)>>1;
build(l,mid,pos<<1);
build(mid+1,r,pos<<1|1);
push_up(pos);
}
void push_down(int pos){
if(tree[pos].mark){
tree[pos<<1].v+=tree[pos].mark;
tree[pos<<1].mark+=tree[pos].mark;
tree[pos<<1|1].v+=tree[pos].mark;
tree[pos<<1|1].mark+=tree[pos].mark;
tree[pos].mark=0;
}
}
void update(int L,int R,int v,int pos){
if(L<=tree[pos].l&&R>=tree[pos].r){
tree[pos].v+=v;
tree[pos].mark+=v;
return;
}
push_down(pos);
int mid=(tree[pos].l+tree[pos].r)>>1;
if(L<=mid) update(L,R,v,pos<<1);
if(R>mid) update(L,R,v,pos<<1|1);
push_up(pos);
}
int query(int L,int R,int pos){
if(L<=tree[pos].l&&R>=tree[pos].r){
return tree[pos].v;
}
push_down(pos);
int mid=(tree[pos].l+tree[pos].r)>>1;
int ans=0;
if(L<=mid) ans=max(ans,query(L,R,pos<<1));
if(R>mid) ans=max(ans,query(L,R,pos<<1|1));
return ans;
} int nex[maxn];
void init(){
stack<int>s;
for(int i=n;i>=1;i--){
while(!s.empty()&&a[s.top()]<=a[i]) s.pop();
if(!s.empty()){
int p=s.top();
add_edge(p,i);
add_edge(i,p);
}else{
add_edge(n+1,i);
add_edge(i,n+1);
}
s.push(i);
}
dfs(n+1,0);
}
int main(){
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
init();
build(1,n+1,1);
for(int i=1;i<=k;i++){
update(lb[i],rb[i],1,1);
}
for(int i=1;i+k-1<=n;i++){
int r=i+k-1;
printf("%d ",query(1,n+1,1));
update(lb[i],rb[i],-1,1);
update(lb[r+1],rb[r+1],1,1);
}
}

Codeforces 1132G(dfs序+线段树)的更多相关文章

  1. CodeForces 877E DFS序+线段树

    CodeForces 877E DFS序+线段树 题意 就是树上有n个点,然后每个点都有一盏灯,给出初始的状态,1表示亮,0表示不亮,然后有两种操作,第一种是get x,表示你需要输出x的子树和x本身 ...

  2. Codeforces 396C (DFS序+线段树)

    题面 传送门 题目大意: 给定一棵树,每个点都有权值,边的长度均为1,有两种操作 操作1:将节点u的值增加x,并且对于u的子树中的任意一个点v,将它的值增加x-dist(u,v)*k, dist(u, ...

  3. Codeforces 1110F(DFS序+线段树)

    题面 传送门 分析 next_id = 1 id = array of length n filled with -1 visited = array of length n filled with ...

  4. Educational Codeforces Round 6 E dfs序+线段树

    题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili ...

  5. Codeforces 343D Water Tree(DFS序 + 线段树)

    题目大概说给一棵树,进行以下3个操作:把某结点为根的子树中各个结点值设为1.把某结点以及其各个祖先值设为0.询问某结点的值. 对于第一个操作就是经典的DFS序+线段树了.而对于第二个操作,考虑再维护一 ...

  6. Codeforces Round #442 (Div. 2)A,B,C,D,E(STL,dp,贪心,bfs,dfs序+线段树)

    A. Alex and broken contest time limit per test 2 seconds memory limit per test 256 megabytes input s ...

  7. CodeForces 877E Danil and a Part-time Job(dfs序+线段树)

    Danil decided to earn some money, so he had found a part-time job. The interview have went well, so ...

  8. 【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心

    3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 130[Submit][Status][Discuss] D ...

  9. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

    题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...

随机推荐

  1. 华为Android手机打开Log

    华为Android手机打开Log, 显示日志方法 今天在华为u8650上调试应用程序时,发现Eclipse的log始终无法显示,在网上找了好多资料,甚至stack overflow也查了,最后终于找到 ...

  2. C语言接口

    struct i_foo * foobar_foo(void); //返回接口指针struct foo_object * foo_create(struct i_foo *iface, void *d ...

  3. 前端对base64编码的理解,原生js实现字符base64编码

    目录 常见对base64的认知(不完全正确) 多问一个为什么,base64到底是个啥? 按照我们的思路实现一下 到这里基本就实现了,结果跟原生的方法打印的是一样的 下一次 @( 对于前端工程师来说ba ...

  4. 抓包工具Charles简单使用介绍(可抓取Android中app的请求)

    摘自: 作者:Roy_Liang链接:http://www.jianshu.com/p/5539599c7a25 Charles安装 HTTP抓包 HTTPS抓包   1. Charles安装 官网下 ...

  5. CS184.1X 计算机图形学导论(第五讲)

    一.观察:正交投影 1.特性:保持平行线在投影后仍然是平行的 2.一个长方体,对处在只有深度不同的位置上的同一物体来说,它的大小不会改变. 3.透视投影:平行线在远处会相交(例如铁轨) 4.glOrt ...

  6. [BZOJ1018][SHOI2008]堵塞的交通traffic 时间分治线段树

    题面 介绍一种比较慢的但是好想的做法. 网上漫天的线段树维护联通性,然后想起来费很大周折也很麻烦.我的做法也是要用线段树的,不过用法完全不同. 这个东西叫做时间分治线段树. 首先我们建一个\(1..m ...

  7. MySQL查询执行路径

    1.客户端发送一条查询给服务器2.服务器先检查查询缓存,如果命中缓存,则立刻返回存储在缓存中的结果.3.服务器端进行SQL解析.预处理,再由优化器生成对应的执行计划.4.MySQL根据优化器生成的执行 ...

  8. 【FTP】FTP(文件传输协议)工作原理(SFTP)

    目前在网络上,如果你想把文件和其他人共享.最方便的办法莫过于将文件放FTP服务器上,然后其他人通过FTP客户端程序来下载所需要的文件. 1.FTP架构 如同其他的很多通讯协议,FTP通讯协议也采用客户 ...

  9. java通过url调用远程接口返回json数据

    java通过url调用远程接口返回json数据,有用户名和密码验证, 转自 https://blog.csdn.net/wanglong1990421/article/details/78815856 ...

  10. 比传统事务快10倍?一张图读懂阿里云全局事务服务GTS

    近日,阿里云全局事务服务GTS正式上线,为微服务架构中的分布式事务提供一站式解决方案.GTS的原理是将分布式事务与具体业务分离,在平台层面开发通用的事务中间件GTS,由事务中间件协调各服务的调用一致性 ...