Weed

Time Limit: 20 Sec  Memory Limit: 512 MB

Description

  从前有个栈,一开始是空的。
  你写下了 m 个操作,每个操作形如 k v :
    若 k = 0,代表往栈顶加入一个数 v
    若 k = 1,则代表从栈顶弹出 v 个数,如果栈中的元素少于 v 个,则全部弹出。
  接着你又进行了 q 次修改,每次你会选择一个操作,并且修改它的两个参数。
  在每次修改后,你都要求出如果依次执行这些操作,最后栈中剩下的元素之和。

Input

  第一行两个正整数 m,q,分别表示操作数和修改次数。
  接下来 m 行,每行两个整数 k,v,代表一个操作。
  接下来 q 行,每行三个正整数 c,k,v,表示将第 c 个操作的参数修改为 k 和 v。

Output

  输出 q 行,每行一个整数,代表依次执行所有操作后栈中剩下的元素之和。

Sample Input

  5 2
  0 3
  0 2
  0 3
  1 1
  0 5
  1 0 3
  1 0 1

Sample Output

  10
  8

HINT

  m,q ≤ 2×1e5, v ≤ 1e4

Solution

  首先,我们可以把一个操作拆成:先删除若干个数,然后加入若干个数

  那么我们可以用线段树来维护,一个节点记录:删除del个数加入add个数这add个数的和是val

  那么我们只需要支持单点修改,答案显然就是Node[1].val。问题在于怎么合并两个节点的信息。

  我们分情况讨论,记录左儿子为L,右儿子为R。显然信息形如:----+++ / -----+++。讨论一下 R.delL.add 的关系:

    1. 显然当 L.add <= R.del 的时候, del 即为 L.del + R剩余的del ,add 即为 R.add,val 即为 R.val

    2. 否则,当 L.add > R.del 的时候,难点在于 L 剩下多少 val,只要讨论出了这个问题,就解决了该题。

  我们令函数 Query(i, k) 表示 删除节点 i后 k 个值,剩下的 val。那么显然这个也只要分类讨论即可:

    1. k = R.add,返回 i.val - R.val 即可,比较显然;

    2. k < R.add,显然我们需要继续往 R 递归,返回 i.val - R.val + Query(R, k)

    3. k > R.add,显然我们需要往 L 递归,显然 k 先减去 R.add,又因为存在R.del这一段,所以 L 的后面几个被删除的,要多查几个,所以返回 Query(L, k - R.add + R.del)

  然后我们写个线段树,就解决了这道题啦QWQ。

Code

 #include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
using namespace std;
typedef long long s64; const int ONE = 1e6 + ; int m, T; struct point
{
int opt, val;
}oper[ONE]; struct power
{
int add, del, val;
}Node[ONE * ]; int get()
{
int res=,Q=;char c;
while( (c=getchar())< || c> )
if(c=='-')Q=-;
res=c-;
while( (c=getchar())>= && c<= )
res=res*+c-;
return res*Q;
} int Query(int i, int k)
{
int L = i << , R = i << | ;
if(k == Node[R].add) return Node[i].val - Node[R].val;
if(k < Node[R].add) return Node[i].val - Node[R].val + Query(R, k);
if(k > Node[R].add) return Query(L, k - Node[R].add + Node[R].del);
} power Merge(int L, int R)
{
power c = (power){, , };
if(Node[L].add <= Node[R].del)
c.del = Node[L].del + Node[R].del - Node[L].add,
c.add = Node[R].add, c.val = Node[R].val;
if(Node[L].add > Node[R].del)
{
c.del = Node[L].del;
c.add = Node[L].add - Node[R].del + Node[R].add;
c.val = Query(L, Node[R].del) + Node[R].val;
}
return c;
} void Build(int i, int l, int r)
{
if(l == r)
{
if(oper[l].opt == ) Node[i] = (power){, , oper[l].val};
else Node[i] = (power){, oper[l].val, };
return;
}
int mid = l + r >> ;
Build(i << , l, mid); Build(i << | , mid + , r);
Node[i] = Merge(i << , i << | ); } void Update(int i, int l, int r, int L)
{
if(L <= l && r <= L)
{
if(oper[l].opt == ) Node[i] = (power){, , oper[l].val};
else Node[i] = (power){, oper[l].val, };
return;
}
int mid = l + r >> ;
if(L <= mid) Update(i << , l, mid, L);
else Update(i << | , mid + , r, L);
Node[i] = Merge(i << , i << | );
} int main()
{
m = get(); T = get();
for(int i = ; i <= m; i++)
oper[i].opt = get(), oper[i].val = get();
Build(, , m);
while(T--)
{
int id = get();
oper[id].opt = get(); oper[id].val = get();
Update(, , m, id);
printf("%d\n", Node[].val);
}
}

【Foreign】Weed [线段树]的更多相关文章

  1. 【BZOJ 2957】楼房重建&&Codechef COT5 Count on a Treap&&【NOIP模拟赛】Weed 线段树的分治维护

    线段树是一种作用于静态区间上的数据结构,可以高效查询连续区间和单点,类似于一种静态的分治.他最迷人的地方在于“lazy标记”,对于lazy标记一般随我们从父区间进入子区间而下传,最终给到叶子节点,但还 ...

  2. Weed:线段树

    观察复杂度,是log级别以下回答询问的. O(1)?逗我kx呢? 自然而然地想到线段树. 学长讲的原题啊考场上还不会打. 线段树上的每个节点都表示一个操作区间. 线段树上维护的权值有3个:这个子区间一 ...

  3. 【模拟8.10】Weed(线段树)

    考试只好随便骗骗分过去啦啦啦..... 正解是玄学线段树: 以每个操作为叶子节点,我们定义几个变量ce表示层数,h表示高度,add表示所减的层数 那么问题转化为单点修改的问题输出直接是根节点答案 但是 ...

  4. 【Foreign】数据结构C [线段树]

    数据结构C Time Limit: 20 Sec  Memory Limit: 512 MB Description Input Output Sample Input Sample Output H ...

  5. 【Foreign】划分序列 [线段树][DP]

    划分序列 Time Limit: 20 Sec  Memory Limit: 256 MB Description Input Output 仅一行一个整数表示答案. Sample Input 9 4 ...

  6. 【Foreign】染色 [LCT][线段树]

    染色 Time Limit: 20 Sec  Memory Limit: 256 MB Description Input Output Sample Input 13 0 1 0 2 1 11 1 ...

  7. 【Foreign】阅读 [线段树][DP]

    阅读 Time Limit: 10 Sec  Memory Limit: 256 MB Description Input Output Sample Input 0 10 4 10 2 3 10 8 ...

  8. [CSP-S模拟测试]:Weed(线段树)

    题目描述 $duyege$的电脑上面已经长草了,经过辨认上面有金坷垃的痕迹.为了查出真相,$duyege$准备修好电脑之后再进行一次金坷垃的模拟实验.电脑上面有若干层金坷垃,每次只能在上面撒上一层高度 ...

  9. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

随机推荐

  1. Calculator Part Ⅰ

    GitHub/object-oriented The title of the work 关于这次的作业,一开始我是觉得不难的,毕竟学长在已经提供了足够多的提示,实现步骤.需要那些方面的知识等等.但是 ...

  2. [基于NetCore的简单博客系统]-登录

    0-项目背景 一个基于.NET CORE RAZOR PAGES的简单博客系统 技术栈全部采用微软官方实现方式,目的是熟悉新技术 项目地址:https://github.com/ganqiyin/BL ...

  3. HDU 5816 Hearthstone 概率dp

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5816 Hearthstone Time Limit: 2000/1000 MS (Java/Othe ...

  4. <Effective C++>读书摘要--Accustoming Youself to C++

    <Item 1>View C++ as a federation of languages. 1.把C++看成4种子语言组成,即C.Object-Oriented C++.Template ...

  5. Web服务器性能压力测试工具

    一.http_load 程序非常小,解压后也不到100K http_load以并行复用的方式运行,用以测试web服务器的吞吐量与负载. 但是它不同于大多数压力测试工具,它可以以一个单一的进程运行,一般 ...

  6. [OS] 多线程--第一次亲密接触CreateThread与_beginthreadex本质区别

    转自:http://blog.csdn.net/morewindows/article/details/7421759 本文将带领你与多线程作第一次亲密接触,并深入分析CreateThread与_be ...

  7. hadoop的第一个hello world程序(wordcount)

    在hadoop生态中,wordcount是hadoop世界的第一个hello world程序. wordcount程序是用于对文本中出现的词计数,从而得到词频,本例中的词以空格分隔. 关于mapper ...

  8. 【题解】CF#855 G-Harry Vs Voldemort

    个人感觉挺有意思的,然而被颜神D无聊惹(- ̄▽ ̄)- 这题我们可以首先试图去统计以每一个点作为 w 点所能对答案造成的贡献是多少.不难发现,当且仅当 u 和 v 都在 w 所在边双的一侧的时候不能构成 ...

  9. [WC2005]双面棋盘

    description 洛谷 给出一个\(n\times n\)的黑白棋盘. \(m\)次操作,每次将一个格子进行颜色翻转,求每次操作后的黑白四连通块数. data range \[n\le 200, ...

  10. bzoj 2424: [HAOI2010]订货 (费用流)

    直接费用流,天数就是点数 type arr=record toward,next,cap,cost:longint; end; const maxm=; maxn=; mm=<<; var ...