线段树-Pudding Monster CF526F-单调栈
生活随笔
收集整理的這篇文章主要介紹了
线段树-Pudding Monster CF526F-单调栈
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Pudding Monster
題目連接:https://www.luogu.org/problem/show?pid=CF526F
問題提出
- 給長度為nnn的排列AAA.
- 問有多少(l,r)(l,r)(l,r),使得將Al,Al+1,...,ArA_l,A_{l+1},...,A_rAl?,Al+1?,...,Ar?排序之后是連續的一段數.
- n≤105n \le 10^5n≤105
問題解決
判斷一段區間是否能連續,只要判斷是否滿足max?min=r?lmax-min=r-lmax?min=r?l即可.
也即判斷區間是否滿足max?min+l=rmax-min+l = rmax?min+l=r.
先天有max?min+l≥rmax-min+l \ge rmax?min+l≥r
因此我們可以考慮枚舉區間端點rrr,然后使用線段樹維護左邊所有區間(每個區間用左端點唯一標識)的l+max?minl+max-minl+max?min的值.
我們還需要線段樹滿足求線段內最小值是誰,最小值有多少個的功能.
考慮到區間右端點向右移動的過程中,原有的區間再加上rrr形成的新區間的maxmaxmax不會變小,minminmin值不會變大.
而maxmaxmax變大也會是一批區間一起增大,增量也是相同的,因此可以轉化為區間修改操作.
我們可以用222個單調棧來維護當前的最大值序列,和最小值序列.
每次將rrr點加入左邊所有的區間,從而形成新的區間,根據單調棧保存的信息,確定出哪些區間的最大值或者是最小值需要被修改,然后進行區間修改.
詢問時候,直接查詢[1,r][1,r][1,r]內最小值為000的個數,算貢獻.
代碼
#include <iostream> #include <algorithm> #include <cstring> #define pr(x) std::cout << #x << ':' << x << std::endl #define rep(i,a,b) for(int i = a;i <= b;++i) #define clr(x) memset(x,0,sizeof(x)) #define setinf(x) memset(x,0x3f,sizeof(x))const int N = 300007,inf = 1e9; int n,m; typedef std::pair<int,int> pii; int a[N];struct node{int val,cnt,tag,len;node(int val = 0,int cnt = 1,int tag = 0,int len = 1):val(val),cnt(cnt),tag(tag),len(len){} }ns[N<<2]; //線段樹維護的是區間最小值以及最小值的個數 inline void pushdown(int o) {if(ns[o].tag) {ns[o<<1].val += ns[o].tag;ns[o<<1|1].val += ns[o].tag;ns[o<<1].tag += ns[o].tag;ns[o<<1|1].tag += ns[o].tag;ns[o].tag = 0;} }inline node maintain(node &lch,node &rch) {node res = node(std::min(lch.val,rch.val),0,0,lch.len+rch.len);if(lch.val == res.val) res.cnt += lch.cnt;if(rch.val == res.val) res.cnt += rch.cnt;return res; }inline void change(int o,int l,int r,int cl,int cr,int val) {if(cl <= l && r <= cr) {ns[o].tag += val;ns[o].val += val;return ;} if(r < cl || cr < l) return;int mid = (l + r) >> 1;pushdown(o);change(o<<1,l,mid,cl,cr,val);change(o<<1|1,mid+1,r,cl,cr,val);ns[o] = maintain(ns[o<<1],ns[o<<1|1]); }inline node query(int o,int l,int r,int ql,int qr) {if(ql <= l && r <= qr) return ns[o];if(r < ql || qr < l)return node(inf,1,0,0);int mid = (l + r) >> 1;pushdown(o);node lch = query(o<<1,l,mid,ql,qr);node rch = query(o<<1|1,mid+1,r,ql,qr);return maintain(lch,rch); }inline void build(int o,int l,int r) {if(l == r) {ns[o] = node(0,1,0,1);return ;}int mid = (l + r) >> 1;build(o<<1,l,mid);build(o<<1|1,mid+1,r);ns[o] = maintain(ns[o<<1],ns[o<<1|1]); }pii mx[N],mi[N]; int topx,topi;int main() {std::cin >> n;build(1,1,n);rep(i,1,n) {int idx,y;std::cin >> idx >> y;a[idx] = y;}long long ans = 0;rep(i,1,n) {change(1,1,n,i,i,i);while(topx > 0 && mx[topx].first < a[i]) {change(1,1,n,mx[topx-1].second+1,mx[topx].second,a[i] - mx[topx].first);topx--;}mx[++topx] = (pii){a[i],i};while(topi > 0 && mi[topi].first > a[i]) {change(1,1,n,mi[topi-1].second+1,mi[topi].second,mi[topi].first - a[i]);topi--;}mi[++topi] = (pii){a[i],i};change(1,1,n,1,i,-i);node res = query(1,1,n,1,i);ans += res.cnt;change(1,1,n,1,i,i);}std::cout << ans << std::endl;return 0; }總結
以上是生活随笔為你收集整理的线段树-Pudding Monster CF526F-单调栈的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2016台式电脑的配置怎么看(2016台
- 下一篇: 剑灵要求电脑配置高吗(剑灵要求电脑配置)