题解 P4747 【[CERC2017]Intrinsic Interval】

ywy_c_asm

2018-12-24 21:26:10

Solution

这题真的是一道思维好题。(感谢$i207M$神犇提供的思路qwq) 首先显而易见的有这个好区间的$max-min=r-l$,不过要做这题光有这个还不够,做这种题的时候就不能把这堆数完全当做离散量来处理,我们还需要找出一些别的性质。 我们发现包含着这段区间的好区间可能会有很多吧,考虑两个包着这个区间的好区间$[l_1,r_1]$和$[l_2,r_2]$,我们只讨论不包含的情况(因为包含的话外层那个区间肯定是没用的),不妨设$l_2>l_1$,那么这两个区间的交$[l_2,r_1]$也是包含着这个询问区间的。既然他是两个好区间的交,我们不妨考虑这样一个问题:$[l_2,r_1]$为什么既能和$[l_1,l_2-1]$拼成一个好区间,又能和$[r_1+1,r_2]$拼成一个好区间?我们发现$[l_2,r_1]$居然也是一个好区间!假如他不好的话,也就是说中间不连续,那么它最多只能和一边的区间拼成好区间。那么我们可以断言,**从$r$开始的第一个能够包住$[l,r]$的好区间的右端点对应的最短能够包住$[l,r]$的好区间就是唯一的答案**(~~这话好绕口啊……~~)。 于是就可以有这样一个思路,我们维护一个扫描线,把这些区间离线下来,然后想办法找出当前点$i$对应的右端点的好区间按照$l$的顺序(用个set维护)直接处理掉。那么考虑如何找所有可行的左端点。 其实题面上已经给了我们一个非常好的提示: _若它的一个子串 $\pi[a..b]$ 排序后是连续正整数,则称 $\pi[a..b]$ 是一个“好区间”。_ 我们发现把这玩意排序之后相邻的两项差为1对吧,那么这个好区间$[l,r]$有多少无序二元组$(i,j)$是相邻两项或者绝对值为1呢?显然就是$r-l$,显然对于无序二元组可以在靠后的那个位置统计。那么我们就可以把好区间换个定义了: _在$[l,r]$内有$r-l$个无序二元组的区间_ 那么我们现在枚举的是$r$,那么直接找$l$后面有多少个二元组即可。于是我们可以把式子变形,不妨设$val[l]$为$l$后面有多少个合法的二元组,那么显然就有$val[l]+l=r$当且仅当$[l,r]$为好区间。于是我们就可以换一种角度进行统计:开一个初始值为下标的线段树,然后我们在扫描线的时候如果发现$a_{i-1}$或者$a_{i+1}$在$i$前面就把1~他们的位置进行区间加,显然值为$i$的位置就是可行的好区间。 那么我们该如何在处理询问的时候找出区间内等于$i$的最后一个位置呢?表面上看起来是不可做的,但是不难发现一个区间内最多只会有$r-l$个合法的二元组(其实就是把他们排序一下看然后就不可能再多了),也就是说等于$i$的位置是区间内的最大值,既然是最大值就可以在线段树上乱搞了。 上代码~ ```cpp #include<iostream> #include<cstdio> #include<cstring> #include<set> #include<vector> #define ls(_o) (_o<<1) #define rs(_o) ((_o<<1)|1) #define up(_o) maxn[_o]=max(maxn[ls(_o)],maxn[rs(_o)]) using namespace std; namespace ywy{ inline int get(){ int n=0;char c;while((c=getchar())||23333){ if(c>='0'&&c<='9')break;if(c=='-')goto s; }n=c-'0';while((c=getchar())||23333){ if(c>='0'&&c<='9')n=n*10+c-'0';else return(n); }s:while((c=getchar())||23333){ if(c>='0'&&c<='9')n=n*10-c+'0';else return(n); } } void print(int num){ if(num>=10)print(num/10);putchar(num%10+'0'); } int ansl[100001],ansr[100001]; typedef struct _qj{ int l;int r;int id; friend bool operator <(const _qj &a,const _qj &b){ if(a.l==b.l)return(a.id<b.id); return(a.l<b.l); } }qj; set<qj> st; int ints[100001],pos[100001],maxn[1000001],adds[1000001]; inline void down(int tree){ if(!adds[tree])return; int cjr=adds[tree]; adds[tree]=0; adds[ls(tree)]+=cjr;adds[rs(tree)]+=cjr; maxn[ls(tree)]+=cjr;maxn[rs(tree)]+=cjr; } int query(int rl,int rr,int l,int r,int tree,int num){//cout<<tree<<endl; down(tree);int mid=(l+r)>>1; if(rl>rr)return(-1); if(rl==l&&rr==r){ if(maxn[tree]!=num)return(-1);if(l==r)return(l); if(maxn[rs(tree)]==num)return(query(mid+1,r,mid+1,r,rs(tree),num)); return(query(l,mid,l,mid,ls(tree),num)); } if(rl>mid)return(query(rl,rr,mid+1,r,rs(tree),num)); if(rr<=mid)return(query(rl,rr,l,mid,ls(tree),num)); int cjr=query(mid+1,rr,mid+1,r,rs(tree),num); if(cjr!=-1)return(cjr); return(query(rl,mid,l,mid,ls(tree),num)); } vector<qj> vec[100001]; void inc(int rl,int rr,int l,int r,int tree){ if(rl==l&&rr==r){ adds[tree]++;maxn[tree]++;return; } int mid=(l+r)>>1;down(tree); if(rl>mid)inc(rl,rr,mid+1,r,rs(tree));else{ if(rr<=mid)inc(rl,rr,l,mid,ls(tree));else{ inc(rl,mid,l,mid,ls(tree)); inc(mid+1,rr,mid+1,r,rs(tree)); } }up(tree); } void build(int l,int r,int tree){ if(l==r){ maxn[tree]=l;return; } int mid=(l+r)>>1; build(l,mid,ls(tree)); build(mid+1,r,rs(tree));up(tree); } typedef set<qj>::iterator it; void ywymain(){ int n=get(); for(register int i=1;i<=n;i++)pos[ints[i]=get()]=i; int m=get(); for(register int i=1;i<=m;i++){ int l=get(),r=get(); qj cjr;cjr.l=l;cjr.r=r;cjr.id=i; vec[r].push_back(cjr); } build(1,n,1); for(register int i=1;i<=n;i++){ if(ints[i]!=1&&pos[ints[i]-1]<i)inc(1,pos[ints[i]-1],1,n,1); if(ints[i]!=n&&pos[ints[i]+1]<i)inc(1,pos[ints[i]+1],1,n,1); for(register int j=0;j<vec[i].size();j++){ st.insert(vec[i][j]); } while(st.begin()!=st.end()){ it lp=st.end();lp--;qj me=*lp; int cjr=query(1,me.l,1,n,1,i); if(cjr==-1)break; ansl[me.id]=cjr; ansr[me.id]=i;st.erase(lp); } } for(register int i=1;i<=m;i++)print(ansl[i]),putchar(' '),print(ansr[i]),putchar('\n'); } } int main(){ ywy::ywymain();return(0);//再见程序 } ```