zoukankan      html  css  js  c++  java
  • CF1132G

    听说,一个好的Oier都是题目喂出来的。

    题目

    定义一个序列的最长贪心严格上升子序列为:若选出的子序列为 (a),对于其中相邻两项 (i,j),不存在 b(i<k<j),满足在原序列 (b) 中,有 (b_i<b_k),换句话说就是选择一个元素后必须选择它之后第一个大于它的元素

    给定一个长度为 (n) 的序列,同时给定一个常数 (k),求该序列的所有长度为 (k)的子区间的最长贪心严格上升子序列的长度

    数据范围(10^6)

    解题思路

    先想了一个长链剖分的假做法,发现不会处理长儿子,自闭了。

    考虑每个点的出度都不超过1,所以他构成了一颗森林

    (f_x)表示从x开始往上走,最长走多远。

    每加入一个点,需要把它的子树内的所有点权值+1

    每删除一个点,需要把它的权值变得足够小

    线段树维护即可

    代码

    #include<bits/stdc++.h>
    #define now edge[i].v
    #define go(x) for(int i=head[x];i;i=edge[i].nxt)
    #define ls o<<1,l,mid
    #define rs o<<1|1,mid+1,r
    using namespace std;
    const int sz=1e6+527;
    int n,k;
    int cnt,T;
    int x,y,z;
    int head[sz];
    int a[sz],ans[sz];
    int dfn[sz],lev[sz];
    stack<int>s;
    struct Edge{
    	int v,nxt;
    }edge[sz];
    struct node{
    	int tag,mx;
    }tr[sz<<2];
    void add(int u,int v){
    	edge[++cnt]=(Edge){v,head[u]};
    	head[u]=cnt;
    }
    void update(int o){
    	tr[o<<1].tag+=tr[o].tag;
    	tr[o<<1|1].tag+=tr[o].tag;
    	tr[o<<1].mx+=tr[o].tag;
    	tr[o<<1|1].mx+=tr[o].tag;
    	tr[o].tag=0;
    }
    void modify(int o,int l,int r){
    	if(x<=l&&r<=y) return (void)(tr[o].mx+=z,tr[o].tag+=z);
    	if(tr[o].tag) update(o);
    	int mid=(l+r)>>1;
    	if(x<=mid) modify(ls);
    	if(y>mid) modify(rs);
    	tr[o].mx=max(tr[o<<1].mx,tr[o<<1|1].mx);
    }
    void dfs(int x){
    	dfn[x]=++T;
    	go(x)
    		dfs(now);
    	lev[x]=T;
    }
    int main(){
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		while(!s.empty()&&a[s.top()]<a[i]){
    			add(i,s.top());
    			s.pop();
    		}
    		s.push(i);
    	}
    	n++;
    	while(!s.empty()){
    		add(n,s.top());
    		s.pop();
    	}
    	dfs(n);
    	for(int i=1;i<=k;i++){
    		x=dfn[i],y=lev[i],z=1;
    		modify(1,1,n);
    	}
    	ans[1]=tr[1].mx;
    	for(int i=k+1;i<n;i++){
    		x=dfn[i],y=lev[i],z=1;
    		modify(1,1,n);
    		x=dfn[i-k],y=lev[i-k],z=-1;
    		modify(1,1,n);
    		ans[i-k+1]=tr[1].mx;
    	}
    	for(int i=1;i<=n-k;i++) printf("%d ",ans[i]);
    }
    

    题目链接

  • 相关阅读:
    【BZOJ4676】Xor-Mul棋盘 拆位+状压DP
    【BZOJ4688】One-Dimensional 矩阵乘法
    【BZOJ4704】旅行 树链剖分+可持久化线段树
    【BZOJ4709】[Jsoi2011]柠檬 斜率优化+单调栈
    【BZOJ4711】小奇挖矿 树形DP
    【BZOJ4715】囚人的旋律 DP
    【BZOJ4712】洪水 树链剖分优化DP+线段树
    服务器相关 HTTP 请求错误
    RSA算法
    公钥和私钥解释
  • 原文地址:https://www.cnblogs.com/river-flows-in-you/p/11300170.html
Copyright © 2011-2022 走看看