题解 排列
可以发现一个序列是好的的条件是
但这样只能判定,不好计数
- 关于区间值域连续段计数:
一个转化是转为对 取到最小值的情况进行计数
在线做法是析合树但我不会
一个离线做法是将询问按右端点排序,扫描线按上式维护最小值及个数
那么扫描到 时若最小值为 0,最小值个数就是以 r 为右端点的连续段数
考虑若查询 内的所有连续段怎么处理
一个想法是对整棵线段树打标记,在每一个 r 处将每个节点的值加入历史答案
于是定义 为节点 最后一次建立快照后还应再建立多少次快照
注意此时 是上一次建立快照后积累的标记,所以要先下传 tag
因为 spread 时一整套调整操作可能还没做完,所以不能判val(p<<1)=0
于是复杂度
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define fir first
#define sec 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, m;
int a[N];
// namespace force{
// set<int> s;
// int f[N][N];
// struct bits{
// int a[N];
// inline void add(int i, int dat) {for (; i<=n; i+=i&-i) a[i]+=dat;}
// inline int query(int i) {int ans=0; for (; i; i-=i&-i) ans+=a[i]; return ans;}
// }bit[N];
// void solve() {
// for (int i=1; i<=n; ++i) {
// s.clear();
// for (int j=i; j<=n; ++j) {
// s.insert(a[j]);
// if (*s.rbegin()-*s.begin()==j-i) ++f[i][j];
// }
// }
// for (int i=1; i<=n; ++i) for (int j=i; j<=n; ++j) f[i][j]+=f[i][j-1];
// for (int j=1; j<=n; ++j) for (int i=1; i<=j; ++i) bit[j].add(i, f[i][j]);
// for (int i=1,l,r; i<=m; ++i) {
// l=read(); r=read();
// printf("%d\n", bit[r].query(r)-bit[r].query(l-1));
// }
// }
// }
namespace task{
vector<pair<int, int>> q[N];
int sta1[N], sta2[N], top1, top2;
int tl[N<<3], tr[N<<3], val[N<<3], tag[N<<3];
ll cnt[N<<3], sum[N<<3], lock[N<<3], ans[N];
#define tl(p) tl[p]
#define tr(p) tr[p]
#define val(p) val[p]
#define sum(p) sum[p]
#define tag(p) tag[p]
#define cnt(p) cnt[p]
#define lock(p) lock[p]
inline void pushup(int p) {
cnt(p)=0;
val(p)=min(val(p<<1), val(p<<1|1));
if (val(p<<1)==val(p)) cnt(p)+=cnt(p<<1);
if (val(p<<1|1)==val(p)) cnt(p)+=cnt(p<<1|1);
}
inline void spread(int p) {
//cout<<"spread: "<<p<<endl;
val(p<<1)+=tag(p); tag(p<<1)+=tag(p);
val(p<<1|1)+=tag(p); tag(p<<1|1)+=tag(p);
if (val(p<<1)==val(p)) sum(p<<1)+=lock(p)*cnt(p<<1), lock(p<<1)+=lock(p);
if (val(p<<1|1)==val(p)) sum(p<<1|1)+=lock(p)*cnt(p<<1|1), lock(p<<1|1)+=lock(p);
lock(p)=tag(p)=0;
#if 0
if (!val(p<<1)) sum(p<<1)+=lock(p)*cnt(p<<1);
if (!val(p<<1|1)) sum(p<<1|1)+=lock(p)*cnt(p<<1|1);
val(p<<1)+=tag(p); tag(p<<1)+=tag(p); lock(p<<1)+=lock(p);
val(p<<1|1)+=tag(p); tag(p<<1|1)+=tag(p); lock(p<<1|1)+=lock(p);
lock(p)=tag(p)=0;
#endif
}
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r;
if (l==r) {val(p)=INF; 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, int dat) {
if (tl(p)==tr(p)) {val(p)=0; cnt(p)=1; return ;}
spread(p);
int mid=(tl(p)+tr(p))>>1;
if (pos<=mid) upd(p<<1, pos, dat);
else upd(p<<1|1, pos, dat);
pushup(p);
}
void upd(int p, int l, int r, int dat) {
//if (p==1) cout<<"upd: "<<l<<' '<<r<<' '<<dat<<endl;
if (l<=tl(p)&&r>=tr(p)) {val(p)+=dat; tag(p)+=dat; return ;}
spread(p);
int mid=(tl(p)+tr(p))>>1;
if (l<=mid) upd(p<<1, l, r, dat);
if (r>mid) upd(p<<1|1, l, r, dat);
pushup(p);
}
int query(int p, int l, int r) {
if (l<=tl(p)&&r>=tr(p)) {
//cout<<"qsum: at "<<p<<' '<<tl(p)<<' '<<tr(p)<<" get "<<sum(p)<<endl;
return sum(p);
}
spread(p);
int mid=(tl(p)+tr(p))>>1; ll ans=0;
if (l<=mid) ans+=query(p<<1, l, r);
if (r>mid) ans+=query(p<<1|1, l, r);
return ans;
}
void locking(int p, int l, int r) {
//cout<<"lock: "<<p<<' '<<l<<' '<<r<<endl;
spread(p);
if (l<=tl(p)&&r>=tr(p)) {++lock(p); return ;}
int mid=(tl(p)+tr(p))>>1;
if (l<=mid) locking(p<<1, l, r);
if (r>mid) locking(p<<1|1, l, r);
}
void solve() {
for (int i=1,l,r; i<=m; ++i) {
l=read(); r=read();
q[r].pb({l, i});
}
build(1, 1, n);
for (int i=1; i<=n; ++i) {
//cout<<"i: "<<i<<endl;
if (i>1) upd(1, 1, i-1, -1); upd(1, i, 1);
while (top1 && a[sta1[top1]]<=a[i]) upd(1, sta1[top1-1]+1, sta1[top1], -a[sta1[top1]]), --top1;
upd(1, sta1[top1]+1, i, a[i]); sta1[++top1]=i;
while (top2 && a[sta2[top2]]>=a[i]) upd(1, sta2[top2-1]+1, sta2[top2], a[sta2[top2]]), --top2;
upd(1, sta2[top2]+1, i, -a[i]); sta2[++top2]=i;
//spread(1); locking(1, 1, i);
++lock(1); sum(1)+=cnt(1); spread(1);
//cout<<"locknum: "<<lock(2)<<endl;
//spread(1); spread(2);
//cout<<val(5)<<endl;
//if (i==4) cout<<val(3)<<endl;
for (auto it:q[i]) ans[it.sec]=query(1, it.fir, i);
//if (i==4) cout<<lock(7)<<endl;
//cout<<"1: "<<val(1)<<' '<<cnt(1)<<endl;
}
for (int i=1; i<=m; ++i) printf("%lld\n", ans[i]);
}
}
signed main()
{
freopen("subsegment.in", "r", stdin);
freopen("subsegment.out", "w", stdout);
n=read();
for (int i=1; i<=n; ++i) a[i]=read();
m=read();
task::solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】