Pudding Monster
題目連接:https://www.luogu.org/problem/show?pid=CF526F
問題提出
- 給長度爲的排列.
- 問有多少,使得將排序之後是連續的一段數.
問題解決
判斷一段區間是否能連續,只要判斷是否滿足即可.
也即判斷區間是否滿足.
先天有
因此我們可以考慮枚舉區間端點,然後使用線段樹維護左邊所有區間(每個區間用左端點唯一標識)的的值.
我們還需要線段樹滿足求線段內最小值是誰,最小值有多少個的功能.
考慮到區間右端點向右移動的過程中,原有的區間再加上形成的新區間的不會變小,值不會變大.
而變大也會是一批區間一起增大,增量也是相同的,因此可以轉化爲區間修改操作.
我們可以用個單調棧來維護當前的最大值序列,和最小值序列.
每次將點加入左邊所有的區間,從而形成新的區間,根據單調棧保存的信息,確定出哪些區間的最大值或者是最小值需要被修改,然後進行區間修改.
詢問時候,直接查詢內最小值爲的個數,算貢獻.
代碼
#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;
}