标签:else 长度 rev 维护 input current 情况 contain const
Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 2506 Accepted Submission(s): 786
给你长度为n的序列, 然后从位置1,寻找单调栈的最大长度
然后修改 v[pos] = val, 再求 单调栈的最大长度
但是队友说是单调栈 ,我就用线段树维护了个单调栈,但是我维护的好像有些SB,就是每次左区间的最大值+(用单调栈跑一次最大长度)
然后完美的T了 ,然后就没管这道题了
后来看了一个人的题解,是这样子分析的
对于每一个区间, 贡献只能从左区间 + 右区间的部分选择
然后 考虑: 两种情况 ,如果 右区间的最大值 <= 左区间最大值,那么右区间肯定没有贡献,为0
然后考虑 :如果右区间的最大值 > 左区间最大值,那么问题可以递归 右区间的左儿子 和 右儿子的情况
这样的复杂度 大概是T*m*logn*logn (单点更新val值一个log 然后每次 合并区间的时候又要一个log)
#include <bits/stdc++.h> using namespace std; const int N = 1e5+10; #define ls rt<<1 #define rs rt<<1|1 int mx[N<<2],cnt[N<<2]; int query(int rt,int l,int r,int v) { if(l==r) return mx[rt] > v; if(mx[rt] <= v) return 0; int m = (l+r)>>1; if(mx[ls] <= v) return query(rs,m+1,r,v); else return cnt[rt]-cnt[ls]+query(ls,l,m,v); } int n,m,v[N]; void build(int rt,int l,int r) { mx[rt] = cnt[rt] =0; if(l == r) { mx[rt]=v[l]; cnt[rt]=1; return ; } int m=(l+r)>>1; build(ls,l,m); build(rs,m+1,r); mx[rt]=max(mx[ls], mx[rs]); cnt[rt] = cnt[ls] + query(rs,m+1,r,mx[ls]); } void update(int rt,int l,int r,int pos,int val) { if(l==r && l == pos) { mx[rt]=val; cnt[rt] = 1; return ; } int m = (l+r)>>1; if(pos <= m) update(ls,l,m,pos,val); else update(rs,m+1,r,pos,val); mx[rt]=max(mx[ls], mx[rs]); cnt[rt] = cnt[ls] + query(rs,m+1,r,mx[ls]); } int main() { //freopen("in.txt","r",stdin); int T; scanf("%d",&T); while (T--) { scanf("%d %d", &n, &m); for(int i=1;i<=n;i++) scanf("%d",&v[i]); build(1,1,n); while (m--) { int pos, val; scanf("%d %d",&pos,&val); //pos位置 更新成val update(1,1,n,pos,val); printf("%d\n",cnt[1]); //还原 update(1,1,n,pos,v[pos]); } } return 0; }
hdu 6406 Taotao Picks Apples 线段树 单点更新
标签:else 长度 rev 维护 input current 情况 contain const
原文地址:https://www.cnblogs.com/Draymonder/p/9535550.html