【经典问题】#176. 栈

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

题目大意

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

$n \le 2\times 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\n",ans[i]);
85     return 0;
86 }

 

 

 

 

END

posted @ 2019-04-21 21:23  AntiQuality  阅读(189)  评论(0编辑  收藏  举报