前言:竟然AK了。
题解:
T1:
随便什么set,或有毅力者手写Splay就能过。
T2:
可以YY出,那条路一定是树的直径。画个图可以发现,假如有更优的路径那一定长于树的直径,这是不存在的。那么求出来后bfs一次就好了。
T3:
求区间两个连续的未出现过的最小值。
可以分开两次做,第一次将1 2,3 4,5 6……合并在一起,求区间mex。
第二次将2 3,4 5,6 7……合并在一起,求区间mex。
然后比较下,就没了。
code:
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
using namespace std;
struct trnode{
int lc,rc,c;
}tr[6500010];int tot=0,root[200010],md;
struct node{
int l,r;
}q[200010];
int n,m,t;
int a[200010],ans[200010];
void update(int &x,int froot,int l,int r,int k,int c)
{
x=++tot;
tr[x]=tr[froot];
if(k<l||k>r) return;
if(l==r){tr[x].c=c;return;}
int mid=(l+r)/2;
if(k<=mid) update(tr[x].lc,tr[froot].lc,l,mid,k,c);
else update(tr[x].rc,tr[froot].rc,mid+1,r,k,c);
tr[x].c=min(tr[tr[x].lc].c,tr[tr[x].rc].c);
}
int findans(int x,int k,int l,int r)
{
if(l==r) return l;
int lc=tr[x].lc,lcc=tr[lc].c,mid=(l+r)/2;
if(lcc<k) return findans(tr[x].lc,k,l,mid);
else return findans(tr[x].rc,k,mid+1,r);
}
int getnum(int x,int l,int r,int k)
{
if(!x) return 0;
if(l==r) return tr[x].c;
int mid=(l+r)/2;
if(k<=mid) return getnum(tr[x].lc,l,mid,k);
else return getnum(tr[x].rc,mid+1,r,k);
}
void cc(int &x,int y)
{
if(x==-1) x=y;
x=min(x,y);
}
int main()
{
scanf("%d %d %d",&n,&m,&t);
for(int i=1;i<=m;i++)
scanf("%d",&a[i]);
for(int i=1;i<=t;i++) scanf("%d %d",&q[i].l,&q[i].r);
memset(ans,-1,sizeof(ans));
md=n/2;
for(int i=1;i<=m;i++) update(root[i],root[i-1],1,md,(a[i]+1)/2,i);
for(int i=1;i<=t;i++)
{
int l=q[i].l,r=q[i].r;
int tmp=findans(root[r],l,1,md);
if(getnum(root[r],1,md,tmp)>=l) continue;
ans[i]=(tmp-1)*2+1;
}
memset(tr,0,sizeof(tr));
memset(root,0,sizeof(root));tot=0;
md=(n-1)/2;
for(int i=1;i<=m;i++) update(root[i],root[i-1],1,md,(a[i])/2,i);
for(int i=1;i<=t;i++)
{
int l=q[i].l,r=q[i].r;
int tmp=findans(root[r],l,1,md);
if(getnum(root[r],1,md,tmp)>=l) continue;
cc(ans[i],tmp*2);
}
for(int i=1;i<=t;i++)
{
if(ans[i]==-1) printf("-1 -1\n");
else printf("%d %d\n",ans[i],ans[i]+1);
}
}