P4747 [CERC2017]Intrinsic Interval

  题面

  接下来就要开始了,听说这是个黑题,我尽量好好写。请准备一下纸和笔(不用)。。。。。

  首先引理1:两个优美区间的交集是优美区间,不含包含的情况,这个应该手模一下就能证明。。。

    引理2:定义一个区间的num就是区间内数值相差1的点对数,那么得到优美区间的等价条件就是l+num=r这个可以理解一下,例如1 7 6的num就是1(对),则1+1<3因此不是优美区间,而5 7 6的num是2则1+2=3所以是优美。证明的话我们可以考虑把序列排序,num就代表从最小值开始加,每次只能加1,能加多少次的,那么在例1中只能连续加一次,例2可以连续加2次就是加到头,这就是优美区间。

    引理3:k+num(k,i)<=i,这个是显然的,点对不能超过区间长度

  然后就是我们的结论:从r枚举优美区间的右端点,第一个能够包住[l,r]的优美区间就是答案

  

  于是上图就出现了,假如我枚举r1算到了l1,然后l2和r2其实是最优解怎么办,但是这种东西是不存在的,因为你由引理1可以知道[l2,r1]也是一个优美区间,那么枚举r1是直接得到l2的,而非l1。

  当然我们不是对没一个区间做一个这样的枚举,那样铁定炸飞,我们应该像CDQ一样,对一堆区间做一遍枚举,信息尽量重复利用。那么我们的思路逐渐清晰,就是要枚举每一个i然后处理所有右端点在i之前的没被回答的询问。

  但是好像又遇到了问题,假设在枚举一个i的时候,我要得到的信息是怎样的,当我要处理询问[l,r]时,我要得到一个最靠右的k使得,k(属于)[1,l],并且k+num(k,i)=i(要找到一个优美区间[k,i]并且能抱住[l,r])。然后就死了,这**怎么用线段树维护啊。。。

  挤细西考一下,有引理3,那么就可以搞了,维护一个k+num(k,i)的最大值及其位置,每次直接查(1,l)中的最大值val,要么=i,要么<i,如果val=i显然合法。那么每次枚举到一个新的点i,就要更新一下区间里的所有点的num,把num(k,i)变成num(k,i+1),其实这个很好维护,就是对于i,和它值差1的就2个,分别是a[i]+1和a[i]-1,它们的位置是pos[a[i]-1],pos[a[i]+1],如果一个pos出现在i之前那么这个i和pos就能组成一对点,所有的1<k<pos都有num(k,i)要+1,因为在1-pos之间的k到i的点对显然多了一对i和pos。

  整理下思路,每次把枚举一对点,把我现在能处理的区间,就是右端点等于i的放到一个待回复集合中,让它左端点有序,原因是如果出现不合法能够快速跳走。我把询问的所有l从大到小排序,直接得到1,l中的k+num(k,i)最大值及最靠右的k,如果小于i那么1,l中任意一个数和i组成的区间都无法满足,剩下一堆区间直接不用算,因为更小的k绝对不可能查出来更大的k+num(k,i),此时一定无法满足,只能等到下一个i才可能满足。然后就结束了。用个堆或者set都行我不会用set。然而某wmz以及二营长还有mikufun都没素质卡分块调块长直接碾标算。。听说还有猿小鲲。。

   

#include<iostream>
#include<queue>
#include<cstdio>
#include<vector>
using namespace std;
const int N=100020;
int a[N],pos[N],ans[N][2],tt,n,m;
struct tree{int l,r,w,p,f;}tr[N*4];
struct node
{
    int l,r,id;
    bool friend operator <(node a,node b)
    {return a.l<b.l;}
};
struct pub{int w,p;};
vector<node> v[N];
priority_queue<node> q;
inline int rd()
{
    int s=0,w=1;
    char cc=getchar();
    while(cc<'0'||cc>'9') {if(cc=='-')w=-1;cc=getchar();}
    while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
    return s*w;
}
inline void change(const register int k,const register int w)
{
    tr[k].w+=w;
    tr[k].f+=w;
}
inline pub merge(const register pub a,const register pub b)
{
    pub c;
    c.w=max(a.w,b.w);
    if(a.w>b.w) c.p=a.p;
    else c.p=b.p;
    return c;
}
inline void updata(const register int k)
{
    tr[k].w=max(tr[k<<1].w,tr[k<<1|1].w);
    if(tr[k<<1].w>tr[k<<1|1].w) tr[k].p=tr[k<<1].p;
    else tr[k].p=tr[k<<1|1].p;
}
inline void down(const register int k)
{
    change(k<<1,tr[k].f);change(k<<1|1,tr[k].f);
    tr[k].f=0;
}
void build(const register int k,const register int l,const register int r)
{
    tr[k].l=l;tr[k].r=r;tr[k].f=0;
    if(l==r){tr[k].p=tr[k].w=l;return;}
    const register int mid=l+r>>1;
    build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    updata(k);
}
void add(const register int k,const register int x,const register int y)
{
    int l=tr[k].l,r=tr[k].r,mid=l+r>>1;
    if(l==x&&r==y){change(k,1);return;}
    if(tr[k].f) down(k);
    if(y<=mid) add(k<<1,x,y);
    else if(x>mid) add(k<<1|1,x,y);
    else add(k<<1,x,mid),add(k<<1|1,mid+1,y);
    updata(k);
}
pub ask(const register int k,const register int x,const register int y)
{
    int l=tr[k].l,r=tr[k].r,mid=l+r>>1;
    if(l==x&&r==y) return (pub){tr[k].w,tr[k].p};
    if(tr[k].f) down(k);
    if(y<=mid) return ask(k<<1,x,y);
    else if(x>mid) return ask(k<<1|1,x,y);
    return merge(ask(k<<1,x,mid),ask(k<<1|1,mid+1,y));
}
int main()
{
    n=rd();
    build(1,1,n);
    for(int i=1;i<=n;i++)
        a[i]=rd(),pos[a[i]]=i;
    m=rd();
    for(int i=1;i<=m;i++)
    {
        int l=rd(),r=rd();
        v[r].push_back((node){l,r,i});
    }
    for(int i=1;i<=n;i++)
    {
        if(a[i]-1>=1&&pos[a[i]-1]<i)add(1,1,pos[a[i]-1]);
        if(a[i]+1<=n&&pos[a[i]+1]<i)add(1,1,pos[a[i]+1]);
        for(int j=0;j<v[i].size();j++) q.push(v[i][j]);
        while(!q.empty())
        {
            node tmp=q.top();
            pub temp=ask(1,1,tmp.l);
            if(temp.w!=i) break;
            else ans[tmp.id][0]=temp.p,ans[tmp.id][1]=i,q.pop();
        }
    }
    for(int i=1;i<=m;i++)printf("%d %d\n",ans[i][0],ans[i][1]);
}
/*
g++ 1.cpp -o 1
./1
7
3 1 7 5 6 4 2
3
3 6
7 7
1 3
*/
View Code

 

  

posted @ 2019-08-06 06:19  starsing  阅读(333)  评论(5编辑  收藏  举报