【题解】P4747 [CERC2017]Intrinsic Interval

首先题上说的区间的充要条件是 maxmin=rl

但是这个不是很好维护,我们转化成 区间内的相邻权值对数 =rl

由于是排列,可以直接存一下每个值得的出现位置,离线之后用扫描线+线段树维护这个东西。

由于相邻权值对数最大就是 rl 所以我们只维护一个最大值就可以了。

线段树上把每个位置 i 的初值设为 i ,每有相邻权值对就加 1 ,如果枚举到 r 时权值等于 r 就说明 [l,r] 合法。

这样我们就可以使用线段树来找到所有合法的区间。

再看怎么找包含一个区间的最短的合法区间。

容易发现这个合法区间满足一个性质:若 pq 都是合法区间,并且 pq ,则 pq 也是合法区间。

于是我们就有了求出最短合法区间的方法:从左到右枚举区间右端点,如果当前右端点对应的有左端点包含询问区间,那么当前右端点和对应的最大的包含当前询问区间的左端点形成的合法区间就是答案。

证明也很简单,如果当前区间为 [l1,r1] ,答案区间为 l2,r2 ,显然 l1l2r1r2 那么 [l2,r1] 也为合法区间且更优,矛盾。

剩下的就很简单了,离线,按右端点排序,从左到右枚举右端点,用线段树维护权值,存一下最大值和最大值最靠右的出现位置,然后处理所有待询问的区间即可。

所有带询问区间可以放到一个按 l 排序的大根堆里,因为 l 大的都没有的话 l 小的也肯定没有。

具体见代码

Code

Copy
#include<bits/stdc++.h> #define N 2001001 #define MAX 2001 using namespace std; typedef long long ll; typedef double db; const ll inf=1e18; inline void read(ll &ret) { ret=0;char c=getchar();bool pd=false; while(!isdigit(c)){pd|=c=='-';c=getchar();} while(isdigit(c)){ret=(ret<<1)+(ret<<3)+(c&15);c=getchar();} ret=pd?-ret:ret; return; } ll n,a[N],m,x,y,p[N]; pair<ll,ll>ans[N]; struct que { ll l,r,data; inline friend bool operator <(que x,que y) { return x.l<y.l; } }; vector<que>v[N]; struct node { ll maxn,maxpos,tag; }seg[N]; inline node operator +(node x,node y) { if(x.maxn>y.maxn) return node{x.maxn,x.maxpos,0}; else return node{y.maxn,y.maxpos,0}; } inline void build(ll pos,ll l,ll r) { if(l==r) seg[pos].maxn=l,seg[pos].maxpos=l; else { ll mid=l+r>>1; build(pos<<1,l,mid); build(pos<<1|1,mid+1,r); seg[pos]=seg[pos<<1]+seg[pos<<1|1]; } return; } inline void add(ll pos,ll num) { seg[pos].maxn+=num; seg[pos].tag+=num; return; } inline void pushdown(ll pos) { add(pos<<1,seg[pos].tag); add(pos<<1|1,seg[pos].tag); seg[pos].tag=0; return; } inline void upgrade(ll pos,ll l,ll r,ll s,ll t,ll num) { if(l>t||r<s) return; else if(l>=s&&r<=t) return add(pos,num); pushdown(pos); ll mid=l+r>>1; upgrade(pos<<1,l,mid,s,t,num); upgrade(pos<<1|1,mid+1,r,s,t,num); seg[pos]=seg[pos<<1]+seg[pos<<1|1]; return; } inline node query(ll pos,ll l,ll r,ll s,ll t) { if(l>=s&&r<=t) return seg[pos]; ll mid=l+r>>1; pushdown(pos); if(mid>=s&&mid<t) return query(pos<<1,l,mid,s,t)+query(pos<<1|1,mid+1,r,s,t); else if(mid>=s) return query(pos<<1,l,mid,s,t); else return query(pos<<1|1,mid+1,r,s,t); } priority_queue<que>q; signed main() { read(n); for(int i=1;i<=n;i++) read(a[i]),p[a[i]]=i; read(m); for(int i=1;i<=m;i++) { read(x); read(y); v[y].push_back(que{x,y,i}); } build(1,1,n); for(int i=1;i<=n;i++) { if(a[i]>1&&p[a[i]-1]<i) upgrade(1,1,n,1,p[a[i]-1],1); if(a[i]<n&&p[a[i]+1]<i) upgrade(1,1,n,1,p[a[i]+1],1); for(int j=0;j<v[i].size();j++) q.push(v[i][j]); while(!q.empty()) { que tmp=q.top(); node temp=query(1,1,n,1,tmp.l); if(temp.maxn!=i) break; ans[tmp.data].first=temp.maxpos; ans[tmp.data].second=i; q.pop(); } } for(int i=1;i<=m;i++) printf("%lld %lld\n",ans[i].first,ans[i].second); exit(0); }
posted @   CelticOIer  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?
点击右上角即可分享
微信分享提示