P8251 [NOI Online 2022 提高组] 丹钓战
题意:
有 n 个二元组 (ai,bi),编号为 1 到 n。
有一个初始为空的栈 S,向其中加入元素 (ai,bi) 时,先不断弹出栈顶元素直至栈空或栈顶元素 (aj,bj) 满足 ai≠aj 且 bi<bj,然后再将其加入栈中。
如果一个二元组入栈后栈内只有这一个元素,则称该二元组是“成功的”。
有 q 个询问 li,ri,表示若将编号在 li,ri 中的二元组按编号从小到大依次入栈,会有多少个二元组是“成功的”。
询问之间相互独立。
思路:
首先找找这个单调栈的性质。。。好复杂啊找不出!
正确做法是先模拟一遍题中的单调栈
离线询问,树状数组求区间中小于等于 ki 的数量,还有一种写法 yangege的题解
const signed N = 5e5 + 3;
int n, q, ans[N]; PII p[N];
vector<PII> qry[N]; //qry[l]={<r,id>,...}
int stk[N], top;
struct node {
int val, pos;
} a[N];
bool cmp(node x, node y) {
if(x.val != y.val) return x.val < y.val;
return x.pos > y.pos; //相等的优先处理右边的
}
signed main() {
iofast;
cin >> n >> q;
for(int i = 1; i <= n; i++) cin >> p[i].fi;
for(int i = 1; i <= n; i++) cin >> p[i].se;
for(int i = 1; i <= n; i++) { //模拟单调栈
while(top && (p[stk[top]].fi == p[i].fi
|| p[stk[top]].se <= p[i].se)) top--;
a[i] = {stk[top], i};
stk[++top] = i;
}
for(int i = 1; i <= q; i++) {
int l, r; cin >> l >> r;
qry[l].pb({r,i});
}
sort(a + 1, a + 1 + n, cmp);
for(int i = 1; i <= n; i++) {
int l = a[i].pos;
add(l, 1);
for(auto &[r,id] : qry[l])
ans[id] = ask(r) - ask(l-1);
}
for(int i = 1; i <= q; i++) cout << ans[i] << endl;
}

浙公网安备 33010602011771号