P4747 [CERC2017]Intrinsic Interval

题目链接

题意分析

首先对于一个区间[L,R] 可以发现:Max-Min+L-R=0

如果你不知道该怎么维护的话 请看看这道题【CF526F Pudding Monsters】

现在关键是 对于一个区间怎么维护

首先可以证明的是 一个字串的本征区间是唯一的

因为两个区间的交也是区间 所以两个区间都包含这个区间的话 那么二者的交符合条件而且是更优的

所以我们直接针对长度求最优就可以了

首先 我们把所有的询问子串按照右端点排序 然后进行扫描 扫到的加入一个堆里 按照左端点从大到小进行排序 堆顶的是左端点最大的子串

然后 我们使用线段树维护当前函数 \(f(x)=Max-Min+l-r\) 维护答案的最小值 以及整个最小值最靠右的位置 因为当前右端点确定 所以我们肯定希望左端点尽可能的向右

对于当前堆顶的元素也就是子串 如果说子串的左端点往左存在符合要求的点的话 那么就是我们要求的点

疑点:

1.如果对于一个子串来说 后面存在更优的怎么办?

假设说对于当前的子串求得的本征区间为[L1,R1] 但是实际上对应有更优的L2,R2

那么由于因为两个区间的交也是区间 所以实际上会有更优的[L2,R1]

2.如果堆顶的子串一直找不到答案 那么会不会耽误堆里其他的子串找到答案?

不会有这种情况发生的

你们认为会耽误的只有这种情况

P4747 [CERC2017]Intrinsic Interval

但是为什么会耽误呢?

我们是按照右端点顺序加入堆的 在堆顶元素入堆之前还没有找到答案出堆的话 堆顶的本征区间一定被堆下面子串的本征区间包含的

所以我们就可以好好求了

CODE:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#define N 100080
#define inf 2147483600
using namespace std;
int n,m,tpx,tpy;
int num[N],stx[N],sty[N];
int ansl[N],ansr[N];
struct Node
{
	int le,ri,id;
	friend bool operator < (const Node &A,const Node &B)
	{return A.le==B.le ? A.ri<B.ri : A.le<B.le;}
}qe[N];
priority_queue<Node> que;
struct Tree
{
	int Min,nowat,tag;
}tre[N<<2];
bool cmp(const Node &A,const Node &B)
{return A.ri==B.ri ? A.le<B.le : A.ri<B.ri;}
void pushup(int now)
{
	if(tre[now<<1].Min<tre[now<<1|1].Min)
	{
		tre[now].Min=tre[now<<1].Min;
		tre[now].nowat=tre[now<<1].nowat;
	}
	else
	{
		tre[now].Min=tre[now<<1|1].Min;
		tre[now].nowat=tre[now<<1|1].nowat; 
	}
}
void down(int now)
{
	tre[now<<1].Min+=tre[now].tag;
	tre[now<<1|1].Min+=tre[now].tag;
	tre[now<<1].tag+=tre[now].tag;
	tre[now<<1|1].tag+=tre[now].tag;
	tre[now].tag=0;
}
void build(int now,int le,int ri)
{
	tre[now].tag=0;
	if(le==ri)
	{
		tre[now].Min=le;tre[now].nowat=le;
		return;
	}
	int mid=(le+ri)>>1;
	build(now<<1,le,mid);build(now<<1|1,mid+1,ri);
	pushup(now);
}
void update(int now,int lenow,int rinow,int le,int ri,int d)
{
	if(le<=lenow&&rinow<=ri)
	{
		tre[now].Min+=d;
		tre[now].tag+=d;
		return;
	}
	if(tre[now].tag) down(now);
	int mid=(lenow+rinow)>>1;
	if(le<=mid) update(now<<1,lenow,mid,le,ri,d); 
	if(mid<ri) update(now<<1|1,mid+1,rinow,le,ri,d);
	pushup(now);
}
pair<int,int> query(int now,int lenow,int rinow,int le,int ri)
{
	if(le<=lenow&&rinow<=ri) return make_pair(tre[now].Min,tre[now].nowat);
	if(tre[now].tag) down(now);
	int mid=(lenow+rinow)>>1;pair<int,int> tmp1=make_pair(inf,0),tmp2=make_pair(inf,0);
	if(le<=mid) tmp1=query(now<<1,lenow,mid,le,ri);
	if(mid<ri) tmp2=query(now<<1|1,mid+1,rinow,le,ri);
	if(tmp1.first==tmp2.first)
	{
		if(tmp1.second<tmp2.second) return tmp2;
		else return tmp1;
	}
	else
	{
		if(tmp1.first<tmp2.first) return tmp1;
		else return tmp2;
	}
}
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;++i) cin>>num[i];
	cin>>m;
	for(int i=1,x,y;i<=m;++i)
	{
		cin>>x>>y;qe[i]=(Node){x,y,i};
	}
//	sort(qe+1,qe+m+1);
//	for(int i=1;i<=m;++i)
//	printf("[%d] = (%d %d)\n",i,qe[i].le,qe[i].ri);
	sort(qe+1,qe+m+1,cmp);build(1,1,n);
//	for(int i=1;i<=m;++i)
//	printf("[%d] = (%d %d)\n",i,qe[i].le,qe[i].ri);	
//	for(int i=1;i<=n;++i) printf("%d%c",query(1,1,n,i,i).first,(i==n ? '\n':' '));
	for(int i=1,tail=1;i<=n;++i)
	{
//		printf("now at %d\n",i);
		update(1,1,n,1,n,-1);
//for(int i=1;i<=n;++i) printf("%d%c",query(1,1,n,i,i).first,(i==n ? '\n':' '));		
		while(tail<=m&&qe[tail].ri<=i)
		que.push(qe[tail++]);
		while(tpx&&num[stx[tpx]]<num[i])
		update(1,1,n,stx[tpx-1]+1,stx[tpx],num[i]-num[stx[tpx]]),--tpx;
		stx[++tpx]=i;
		while(tpy&&num[sty[tpy]]>num[i])
		update(1,1,n,sty[tpy-1]+1,sty[tpy],num[sty[tpy]]-num[i]),--tpy;
		sty[++tpy]=i;			
//		printf("che2\n");
		while(!que.empty())
		{
			Node tmp=que.top();
//			printf("now is %d\n",tmp.id); 
			int bian=tmp.le;
//			printf("cdy\n");
			pair<int,int> nowtmp=query(1,1,n,1,bian);		
			if(nowtmp.first==0) 
			{
				ansl[tmp.id]=nowtmp.second;
				ansr[tmp.id]=i;
				que.pop();
			}
			else break;
		}
//		printf("check3\n");
	}
	for(int i=1;i<=m;++i) printf("%d %d\n",ansl[i],ansr[i]);
	return 0;	
}
上一篇:函数的节流和防抖


下一篇:[leetcode] 1523. Count Odd Numbers in an Interval Range