• 【经典问题】#176. 栈


    经典问题:线段树维护单调栈;前置技能:bzoj2957: 楼房重建

    题目大意

    维护$n$个单调栈,要求支持区间加数和单点查询。

    $n le 2 imes 10^5$


    题目分析

    首先考虑单调栈这个问题应该如何转化:将入栈的所有数按加入的时间顺序看成一个序列,得到下图

    那么对于每个时刻$t$的查询,答案就是以$t$为右端点的上升子序列的权值和(注意不是长度)。

    于是单点的子问题就转为经典问题,参见bzoj2957.

    剩下的对于这个序列问题的处理相当套路,由于是区间修改单点查询,并且对于每个点的查询是依靠存在元素的独立询问,那么就先离线对插入序列差分,即在$l$修改$t$时刻的$c$、在$r+1$时刻修改$t$时刻成$0$;剩下对每个栈处理所有询问。这里把$t$时刻处理成0意味着后续时刻的查询就是忽视这个时刻的元素。

    总结一下,对于区间修改单点询问的序列问题,就应该先从单点询问的角度入手,再从离线保留时间序列公用元素的方式降维考虑问题。

    (为什么我这么慢)

     1 #include<bits/stdc++.h>
     2 typedef long long ll;
     3 const int maxn = 200035;
     4 
     5 struct node
     6 {
     7     ll mx,val;
     8 }f[maxn<<2];
     9 struct point
    10 {
    11     int t,d;
    12     point(int a=0, int b=0):t(a),d(b) {}
    13 };
    14 int n,m;
    15 ll ans[maxn];
    16 std::vector<int> qr[maxn];
    17 std::vector<point> opt[maxn];
    18 
    19 int read()
    20 {
    21     char ch = getchar();
    22     int num = 0, fl = 1;
    23     for (; !isdigit(ch); ch=getchar())
    24         if (ch=='-') fl = -1;
    25     for (; isdigit(ch); ch=getchar())
    26         num = (num<<1)+(num<<3)+ch-48;
    27     return num*fl;
    28 }
    29 ll calc(int rt, int c, int l, int r)
    30 {
    31     if (f[rt].mx <= c) return 0;
    32     if (l==r) return (f[rt].mx > c)?f[rt].mx:0;
    33     int mid = (l+r)>>1;
    34     if (f[rt<<1|1].mx <= c) return calc(rt<<1, c, l, mid);
    35     return f[rt].val-f[rt<<1|1].val+calc(rt<<1|1, c, mid+1, r);
    36 }
    37 void modify(int rt, int l, int r, int pos, int c)
    38 {
    39     if (l==r) f[rt].mx = f[rt].val = c;
    40     else{
    41         int mid = (l+r)>>1;
    42         if (pos <= mid) modify(rt<<1, l, mid, pos, c);
    43         if (pos > mid) modify(rt<<1|1, mid+1, r, pos, c);
    44         f[rt].mx = std::max(f[rt<<1].mx, f[rt<<1|1].mx);
    45         f[rt].val = f[rt<<1|1].val+calc(rt<<1, f[rt<<1|1].mx, l, mid);
    46     }
    47 }
    48 int queryMax(int rt, int L, int R, int l, int r)
    49 {
    50     if (L > R) return 0;
    51     if (L <= l&&r <= R) return f[rt].mx;
    52     int mid = (l+r)>>1, ret = 0;
    53     if (L <= mid) ret = queryMax(rt<<1, L, R, l, mid);
    54     if (R > mid) ret = std::max(ret, queryMax(rt<<1|1, L, R, mid+1, r));
    55     return ret;
    56 }
    57 ll query(int rt, int l, int r, int c)
    58 {
    59     if (r <= c) return calc(rt, queryMax(1, r+1, c, 1, m), l, r);
    60     int mid = (l+r)>>1;
    61     if (c <= mid) return query(rt<<1, l, mid, c);
    62     return query(rt<<1, l, mid, c)+query(rt<<1|1, mid+1, r, c);
    63 }
    64 int main()
    65 {
    66     memset(ans, -1, sizeof ans);
    67     n = read(), m = read();
    68     for (int i=1; i<=m; i++)
    69     {
    70         int opd = read();
    71         if (opd==1){
    72             int l = read(), r = read(), x = read();
    73             opt[l].push_back(point(i, x));
    74             opt[r+1].push_back(point(i, 0));
    75         }else qr[read()].push_back(i);
    76     }
    77     for (int i=1; i<=n; i++)
    78     {
    79         for (int j=0; j<(int)opt[i].size(); j++)
    80             modify(1, 1, m, opt[i][j].t, opt[i][j].d);
    81         for (int j=0; j<(int)qr[i].size(); j++) ans[qr[i][j]] = query(1, 1, m, qr[i][j]);
    82     }
    83     for (int i=1; i<=m; i++)
    84         if (ans[i]!=-1) printf("%lld
    ",ans[i]);
    85     return 0;
    86 }

    END

  • 相关阅读:
    英语长难句
    服务器部署 halo博客项目
    11月迟来的总结
    10月总结
    9月总结
    python根据字符串导入模块
    RestFul(番外):类视图更适合restful
    Django-基础 Meta自定义
    (垃圾代码)修改同目录下面的xml文件标签数值
    Django-templatetags设置(在templates中使用自定义变量)
  • 原文地址:https://www.cnblogs.com/antiquality/p/10747039.html
Copyright © 2020-2023  润新知