本题既不是rmq也不会simple(对我这种蒟蒻而言)
一开始只能想到树套树套树TAT然后看了看数据范围果断滚去膜拜题解。
然后才知道预先排序一下可以弄掉一个log。不过得写可持久化线段树套可持久化线段树。。
然后愉悦的开码了。。。感人的是竟然不用调。。。更感人的是交上去直接tle了。
然后从网上找了别人的代码(方法一样)发现同样的数据我要跑6s+。。标称只要2s+。。
之后各种卡常还是慢了一倍TAT。。。最后自己写个max函数就和标程一样快了TAT这几天怎么总是出些奇怪的状况QAQ。
本来故事到这里就应该结束了。。等评测的时候连标题都想好了:“一个max函数引发的惨剧”
然而交上去还是tle了(掀桌。。。然后发现标程也tle了。。。然后想起一开始的时候标程数组范围开小。。在看了下hint。。果然出题人把数据加强了不少。大概结局就是写树套树的都tle了。。。。。。。。。。。。。。。。。老板来一打刀片?
具体做法:用pre[i]和next[i]表示前后最近的与第i个数字相同的数字的位置。在区间[l,r]中只出现一次的数字(假设是第i个位置上的数)一定满足pre[i]<l,且next[i]>r。
直接强行搞的话要三个log。。或者是kd树什么的(三维)。
然后根据Po姐的题解可得(TAT),我们先把各个数字按照pre值升序排序,按新的顺序,把另外的两个值(next和位置)插入到线段树套线段树里面(外层是按next值,内层是位置)。
持久化一下,每次查询的时候就在 pre值<l的最后一个数 插入后的那个版本的树套树里面查询。插入的时候外层新增那条链上的内层线段树,在上一个版本的基础上新增一条链就好了。
按pre值排序和按next值排序都是一样的道理。。
时间复杂度O(m log²n),空间复杂度O(n log²n)....
直接贴tle的代码
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=100233; 7 struct poi{ 8 int pos,pr,af,num; 9 }a[maxn]; 10 int pr[maxn],af[maxn]; 11 int rt_out[maxn],rt[maxn*18],lc[maxn*18],rc[maxn*18],tt; 12 int mx[400*maxn],l[400*maxn],r[400*maxn],tot; 13 int i,j,n,m,L,R,lastans,v,v1; 14 15 int ra;char rx; 16 inline int read(){ 17 rx=getchar(),ra=0; 18 while(rx<'0'||rx>'9')rx=getchar(); 19 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra; 20 } 21 char qaq[7];int len; 22 inline void outx(int x){ 23 if(!x){puts("0");return;} 24 while(x)qaq[len++]=x%10,x/=10; 25 while(len)putchar(qaq[--len]+'0');putchar(' '); 26 } 27 inline int max(int x,int y){return x<y?y:x;} 28 29 30 inline void ins(int pre,int &x,int L,int R){ 31 x=++tot,mx[x]=mx[pre]; 32 if(a[i].num>mx[x])mx[x]=a[i].num; 33 if(L==R)return; 34 register int mid=(L+R)>>1; 35 if(v<=mid)r[x]=r[pre],ins(l[pre],l[x],L,mid); 36 else l[x]=l[pre],ins(r[pre],r[x],mid+1,R); 37 } 38 int zs; 39 inline int getmx(int x,int L,int R,int c,int d){ 40 if(!x)return 0; 41 if(c<=L&&d>=R)return mx[x];register int mid=(L+R)>>1; 42 if(c>mid)return getmx(r[x],mid+1,R,c,d);else 43 if(d<=mid)return getmx(l[x],L,mid,c,d);else 44 return max(getmx(l[x],L,mid,c,d),getmx(r[x],mid+1,R,c,d)); 45 46 } 47 48 49 50 51 inline void insert(int pre,int&x,int L,int R){ 52 x=++tt,ins(rt[pre],rt[x],1,n); 53 if(L==R)return; 54 register int mid=(L+R)>>1; 55 if(v1<=mid)rc[x]=rc[pre],insert(lc[pre],lc[x],L,mid); 56 else lc[x]=lc[pre],insert(rc[pre],rc[x],mid+1,R); 57 } 58 inline int query(int x,int l,int r,int c,int d){ 59 if(!x)return 0; 60 if(c<=l&&d>=r)return getmx(rt[x],1,n,L,R); 61 register int mid=(l+r)>>1; 62 if(c>mid)return query(rc[x],mid+1,r,c,d); 63 else return max(getmx(rt[rc[x]],1,n,L,R),query(lc[x],l,mid,c,d)); 64 } 65 66 67 68 69 bool cmp(poi a,poi b){return a.pr<b.pr;} 70 int main(){ 71 n=read(),m=read(); 72 for(i=1;i<=n;i++)a[i].pos=i,a[i].pr=pr[a[i].num=read()],pr[a[i].num]=i; 73 for(i=n;i;i--)a[i].af=af[a[i].num]?af[a[i].num]:(n+1),af[a[i].num]=i; 74 sort(a+1,a+1+n,cmp); 75 for(i=1;i<=n;i++)v=a[i].pos,v1=a[i].af,insert(rt_out[i-1],rt_out[i],1,n+1); 76 for(i=1;i<=m;i++){ 77 L=read()+lastans,R=read()+lastans; 78 if(L>=n)L%=n;if(R>=n)R%=n; 79 L++,R++;if(L>R)swap(L,R); 80 register int l=1,r=n,mid; 81 for(;l<r;a[mid].pr<L?(l=mid):(r=mid-1)) mid=(l+r+1)>>1; 82 lastans=query(rt_out[l],1,n+1,R+1,n+1); 83 outx(lastans); 84 } 85 return 0; 86 }