题解 [NOI Online 2022 提高组] 丹钓战
读错题花了一点时间
发现可以扫描线,每次找最大的单调栈中的 \(t\) 满足 \(a_t\neq a_i\and b_t>b_i\),对区间 \([t+1, i]\) 产生 1 贡献
那么线段树可以做到 \(O(n\log n)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 500010
#define fst first
#define snd second
#define pb push_back
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, q;
int a[N], b[N];
vector<pair<int, int>> que[N];
namespace force{
int sta[N], top, ans;
void solve() {
for (int i=1,l,r; i<=q; ++i) {
l=read(); r=read(); top=ans=0;
for (int j=l; j<=r; ++j) {
while (top && !(a[j]!=a[sta[top]]&&b[j]<b[sta[top]])) --top;
if (!top) ++ans;
sta[++top]=j;
}
printf("%d\n", ans);
}
}
}
namespace task1{
int tem[N];
int sta[N], ans[N], top;
void solve() {
for (int i=1,l,r; i<=q; ++i) {
l=read(); r=read();
que[r].pb({l, i});
}
for (int i=1; i<=n; ++i) {
// cout<<"i: "<<i<<endl;
int pos=0;
for (int j=1; j<=top; ++j) if (a[sta[j]]!=a[i] && b[sta[j]]>b[i]) pos=sta[j];
// cout<<"pos: "<<pos<<endl;
for (int j=pos+1; j<=i; ++j) ++tem[j];
for (auto it:que[i]) ans[it.snd]=tem[it.fst];
while (top && !(a[i]!=a[sta[top]]&&b[i]<b[sta[top]])) --top;
sta[++top]=i;
}
for (int i=1; i<=q; ++i) printf("%d\n", ans[i]);
}
}
namespace task2{
int sta[N], bit[N], ans[N], top;
int tl[N<<2], tr[N<<2];
pair<int, int> fir[N<<2], sec[N<<2];
#define tl(p) tl[p]
#define tr(p) tr[p]
#define fir(p) fir[p]
#define sec(p) sec[p]
inline void upd(int i, int dat) {for (; i<=n; i+=i&-i) bit[i]+=dat;}
inline int query(int i) {int ans=0; for (; i; i-=i&-i) ans+=bit[i]; return ans;}
inline void pushup(int p) {
fir(p)=fir(p<<1).fst>fir(p<<1|1).fst?fir(p<<1):fir(p<<1|1);
sec(p)={0, 0};
if (fir(p<<1).snd!=fir(p).snd && fir(p<<1).fst>sec(p).fst) sec(p)=fir(p<<1);
if (fir(p<<1|1).snd!=fir(p).snd && fir(p<<1|1).fst>sec(p).fst) sec(p)=fir(p<<1|1);
if (sec(p<<1).snd!=fir(p).snd && sec(p<<1).fst>sec(p).fst) sec(p)=sec(p<<1);
if (sec(p<<1|1).snd!=fir(p).snd && sec(p<<1|1).fst>sec(p).fst) sec(p)=sec(p<<1|1);
}
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r;
if (l==r) return ;
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
pushup(p);
}
void upd(int p, int pos, pair<int, int> val) {
if (tl(p)==tr(p)) {fir(p)=val; return ;}
int mid=(tl(p)+tr(p))>>1;
if (pos<=mid) upd(p<<1, pos, val);
else upd(p<<1|1, pos, val);
pushup(p);
}
int findmx(int p, int ban, int k) {
if (tl(p)==tr(p)) return (fir(p).fst>k&&fir(p).snd!=ban)?tl(p):0;
int maxr=0;
if (fir(p<<1|1).snd!=ban) maxr=max(maxr, fir(p<<1|1).fst);
if (sec(p<<1|1).snd!=ban) maxr=max(maxr, sec(p<<1|1).fst);
if (maxr>k) return findmx(p<<1|1, ban, k);
else return findmx(p<<1, ban, k);
}
void solve() {
// cout<<double(sizeof(tl)*2+sizeof(fir)*2)/1000/1000<<endl; exit(0);
for (int i=1,l,r; i<=q; ++i) {
l=read(); r=read();
que[r].pb({l, i});
}
build(1, 1, n);
for (int i=1; i<=n; ++i) {
// cout<<"i: "<<i<<endl;
int pos=findmx(1, a[i], b[i]);
// for (int j=1; j<=top; ++j) if (a[sta[j]]!=a[i] && b[sta[j]]>b[i]) pos=sta[j];
// cout<<"pos: "<<pos<<endl;
// for (int j=pos+1; j<=i; ++j) ++tem[j];
upd(pos+1, 1); upd(i+1, -1);
for (auto it:que[i]) ans[it.snd]=query(it.fst);
while (top && !(a[i]!=a[sta[top]]&&b[i]<b[sta[top]])) upd(1, sta[top--], {0, 0});
sta[++top]=i; upd(1, sta[top], {b[i], a[i]});
}
for (int i=1; i<=q; ++i) printf("%d\n", ans[i]);
}
}
signed main()
{
freopen("stack.in", "r", stdin);
freopen("stack.out", "w", stdout);
n=read(); q=read();
for (int i=1; i<=n; ++i) a[i]=read();
for (int i=1; i<=n; ++i) b[i]=read();
// force::solve();
// task1::solve();
task2::solve();
return 0;
}