栈和队列小刷

栈和队列

bzoj1012// JSOI2008 最大数 maxnumber

详见博客:https://www.cnblogs.com/tyner/p/11267630.html

bzoj2086 [Poi2010]Blocks

https://www.luogu.org/problem/P3503

题意

给出 N 个正整数 a[1...N],再给出一个正整数 k,现在可以进行
如下操作:
每次选择一个大于 k 的正整数 a[i],将 a[i] 减去 1,选择a[i - 1] 或 a[i + 1] 中的一个加上 1。
经过一定次数的操作后,问最大能够选出多长的一个连续子序列,使得这个子序列的每个数都不小于 k。
总共给出 M 次询问,每次询问给出的 k 不同,你需要分别回答。
(N <= 1000000)(M <= 50)(k <= \(10^9\))
保证答案都在 long long 以内

分析

首先要明确一下,这里的M<=50,说明它需要O(n)的算法(不然它不就只让你修改一次,然后O(nlogn)水掉嘛....)(老师分析的,自己没往这儿想....以后注意一下吧)

其次:要求子序列的每个数都>=k,结合题目中的操作,即需要子序列的平均数>=k。(只要它的平均数>=k, 然后你把较大的几个数-1,然后往较小的数那里传,这样它一定阔以使每个数>=k的这个我又没想出来....)

然后,让平均数>=k,只需把每个数都减上k,使他们的和>=0即可(这个很容易想到...吧),快速维护一个区间和就用个前缀和sum就行了。

重点: 当i < j && sum[i] <= sum[j]时, i 做为左边界一定是比 j 更优的。所以我们维护一个sum单调递减的栈,在用一个指针n->0扫一遍,每次不断弹栈(不用从头重新找),更新答案

#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
const int MAXN = 1000000+99;

int n,m;
ll a[MAXN], sum[MAXN];
int q[MAXN];
ll k;

void solve(ll k) {
    int ans = 0;
    for(int i = 1; i <= n; i++) sum[i] = sum[i-1]+a[i]-k;
    int l = 0, r = 0;
    for(int i = 1; i <= n; i++)
        if(sum[q[r]] > sum[i]) q[++r] = i;//l更优,所以这样做
    for(int i = n, j = r; i >= 1; i--) {//保证i在右边
        while(j>l && sum[i]-sum[q[j-1]] >= 0) --j;//注意判非空
        //因为要把j左移一,所以比较的是q[j-1]的sum和i的
        ans = max(ans, i-q[j]);
    }
    printf("%d",ans);
}

int main() {
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i++) scanf("%lld",&a[i]);
    for(int i = 1; i <= m; i++) {
        scanf("%lld",&k);
        solve(k);
        if(i != m) printf(" ");
    }
}

[JLOI2012] 树

题意

给定一个值 S 和一棵树。在树的每个节点有一个正整数,问有多少条路径的节点总和为 S 。路径中节点的深度必须是升序的。
假设节点 1 是根节点,根的深度是 0,它的儿子节点的深度为1。路径不必一定从根节点开始。

分析

(不知道这题的单调队列做法,看到题解说可以用前缀和,然后就...这样了)

因为题目中限制深度必须升序,所以就是dfs到底的一条链,且每个节点都有一个正整数,所以他们的前缀和都不同,所以我们只需边dfs边往set里加sum[i], 每加入一个就在set里面找有没有值等于sum[i]-s, 统计答案即可。

注意dfs结束时erase当前节点的sum

#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
const int MAXN = 100000+99;
const int MAXM = MAXN<<1;

int n,S,ans;
int sum[MAXN];
set <int> s;

int head[MAXN], cnt;
struct seg{
    int y, next;
}e[MAXM];
void add_edge(int x, int y) {
    e[++cnt].y = y;
    e[cnt].next = head[x];
    head[x] = cnt;
}

void dfs(int x, int fa) {
    sum[x] += sum[fa];
    s.insert(sum[x]);
    if(s.count(sum[x]-S)) ans++;
    for(int i = head[x]; i; i = e[i].next)
        if(e[i].y != fa)
            dfs(e[i].y, x);
    s.erase(sum[x]);//记着清除
}

int main() {
    scanf("%d%d",&n,&S);
    for(int i = 1; i <= n; i++) scanf("%d",&sum[i]);
    int x, y;
    for(int i = 1; i < n; i++) {
        scanf("%d%d",&x,&y);
        add_edge(x, y);
        add_edge(y, x);
    }
    s.insert(0);//有的恰为s
    dfs(1, 0);
    printf("%d",ans);
}

原文地址:https://www.cnblogs.com/tyner/p/11379435.html

时间: 2024-10-07 05:27:32

栈和队列小刷的相关文章

转:栈和队列小知识【STL用法】

原文出处:http://blog.csdn.net/chenzhenyu123456/article/details/44519943 栈: (一)头文件  #include<stack> (二)定义栈  stack<int>s; (三)使用 1 :  s.empty()                               栈为空返回true,否则返回false: 2 :  s.size()                                   返回栈中元素的

c++刷题(3/100)数独,栈和队列

stack的基本操作 ? s.size():返回栈中的元素数量 ? s.empty():判断栈是否为空,返回true或false ? s.push(元素):返回对栈顶部"元素"的可变(可修改)引用 ? s.pop():删除栈顶元素,类型为void,但并不返回被删除的元素 ? s.top():返回栈顶,不删除? s1==s2:若成立,表明s1中的每个元素都等于s2的对应元素,返回true或是false 题目1:用两个栈实现队列 https://www.nowcoder.com/pract

leecode刷题(26)-- 用栈实现队列

leecode刷题(26)-- 用栈实现队列 用栈实现队列 使用栈实现队列的下列操作: push(x) -- 将一个元素放入队列的尾部. pop() -- 从队列首部移除元素. peek() -- 返回队列首部的元素. empty() -- 返回队列是否为空. 示例: MyQueue queue = new MyQueue(); queue.push(1); queue.push(2); queue.peek(); // 返回 1 queue.pop(); // 返回 1 queue.empty

关于栈和队列的一点点小知识-----C++自带函数

栈和队列我们可以用C++里自带的函数使用,就不必手写了 1.栈,需要开头文件 #include<stack>  定义一个栈s:stack<int> s; 具体操作: s.empty()               如果栈为空返回true,否则返回false s.size()                   返回栈中元素的个数 s.pop()                   删除栈顶元素但不返回其值 s.top()                    返回栈顶的元素,但不删

C语言中堆、栈、队列

C语言中堆.栈和队列: 1.堆和栈 (1)数据结构的堆和栈 堆栈是两种数据结构. 栈(栈像装数据的桶或箱子):是一种具有后进先出性质的数据结构,也就是说后存放的先取,先存放的后取.这就如同要取出放在箱子里面底下的东西(放入的比较早的物体),首先要移开压在它上面的物体(放入的比较晚的物体). 堆(堆像一棵倒过来的树):是一种经过排序的树形数据结构,每个结点都有一个值.通常所说的堆的数据结构,是指二叉堆.堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆.由于堆的这个特性,常用来实现优

数据结构和算法分析(9)表栈和队列的实际应用(一)

    在接下来的几篇博文中,将介绍表.栈.队列在编程实践中的应用.     (1)表达式求值:     输入一个中缀表达式,操作符包括(+ - * / ^).转化为后缀表达式之后并计算表达式的值: 要求: 1.输入的中缀表达式必须是一个完整的字符串: 2.不限制数字的位数和正负,负数用()括起来: 代码如下: 1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 5 #define EmptyT

3-9-模拟银行排队过程-栈和队列-第3章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第3章  栈和队列 - 模拟银行排队过程 ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? Status.h.SinglyLinkedList.c.LinkQueue

栈和队列的面试题Java实现

栈和队列的面试题Java实现 二.栈和队列: 面试的时候,栈和队列经常会成对出现来考察.本文包含栈和队列的如下考试内容: (1)栈的创建 (2)队列的创建 (3)两个栈实现一个队列 (4)两个队列实现一个栈 (5)设计含最小函数min()的栈,要求min.push.pop.的时间复杂度都是O(1) (6)判断栈的push和pop序列是否一致 1.栈的创建: 我们接下来通过链表的形式来创建栈,方便扩充. 代码实现: 1 public class Stack { 2 3 public Node he

栈和队列常见题型(java版)

直接上干货..... 栈和队列常见题型: 实现栈和实现队列. 两个栈实现一个队列. 设计栈,使得pop,push和min时间复杂度为O(1). 滑动窗口的最大值. 栈的进出序列. 实现栈和实现队列 主要包括:栈,队列,循环队列. package com.sywyg; /** * 实现栈 * 数组应该是Object类型的 * 注意top的设置影响出栈和获取栈顶元素. * size也可以用top代替 */ class MyStack<E>{ // 栈元素个数 private int size; /