传送门
这个题我实在不知道怎么办了,到现在依然没能在bzojAC,本机测试速度还可以,复杂度似乎也没问题,希望有大佬能指出一下错误!
问题已解决,加个剪枝就好了(果然kd-tree还是离不开剪枝啊)!
我的思路大概是对于每个数记录它的上一次出现的位置(pre_i),当前位置(i),下次出现位置(nxt_i)
按照(pre)排序,对于(i)和(nxt)建立k-d tree,由于涉及到单点修改,所以记录一下从根到每个点的路径,这样能保证在(log_n)的时间内完成修改。
按理说复杂度应该是过得去的,可能是本人的常数实在写得大!!
TLE代码(可持久化k-d tree):
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
void read(int &x) {
char ch; bool ok;
for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define rg register
#define pushup(x) s[x].sum=max(max(s[s[x].l].sum,s[s[x].r].sum),s[x].v)
const int maxn=1e5+1;
struct oo{int d[2],mn[2],mx[2],l,r,sum,v;}s[maxn*20];
struct o{int d[3],id,x;}f[maxn];
int n,m,rt[maxn],w[maxn],g,id,ans,d[maxn],c[maxn];
bool cmp(oo a,oo b){return a.d[g]<b.d[g];}
bool cmp1(o a,o b){return a.d[2]<b.d[2];}
inline void update(int x)
{
if(s[x].l)
{
s[x].mn[0]=min(s[s[x].l].mn[0],s[x].mn[0]);
s[x].mn[1]=min(s[s[x].l].mn[1],s[x].mn[1]);
s[x].mx[0]=max(s[s[x].l].mx[0],s[x].mx[0]);
s[x].mx[1]=max(s[s[x].l].mx[1],s[x].mx[1]);
}
if(s[x].r)
{
s[x].mn[0]=min(s[s[x].r].mn[0],s[x].mn[0]);
s[x].mn[1]=min(s[s[x].r].mn[1],s[x].mn[1]);
s[x].mx[0]=max(s[s[x].r].mx[0],s[x].mx[0]);
s[x].mx[1]=max(s[s[x].r].mx[1],s[x].mx[1]);
}
}
inline void build(int l,int r,int fa,int d,int v,int dep)
{
int mid=(l+r)>>1;g=d;
nth_element(s+l,s+mid,s+r+1,cmp);
s[mid].mn[0]=s[mid].mx[0]=s[mid].d[0];if(!v)s[fa].l=mid;else s[fa].r=mid;
s[mid].mn[1]=s[mid].mx[1]=s[mid].d[1];c[s[mid].d[0]]=c[s[fa].d[0]]|(v<<dep);
if(l!=mid)build(l,mid-1,mid,!d,0,dep+1);
if(r!=mid)build(mid+1,r,mid,!d,1,dep+1);
update(mid);return ;
}
inline void change(int x,int &k,int l,int r,int val,int dep)
{
k=++id,s[k]=s[x];
if(l==s[k].d[0]){s[k].v=val,s[k].sum=max(s[k].sum,val);return ;}
change((c[l]&(1<<(dep+1)))?s[x].r:s[x].l,(c[l]&(1<<(dep+1)))?s[k].r:s[k].l,l,r,val,dep+1);
pushup(k);
}
inline void get(int x,int l,int r,int ll,int rr)
{
if(l<=s[x].mn[0]&&r>=s[x].mx[0]&&ll<=s[x].mn[1]&&rr>=s[x].mx[1]){ans=max(ans,s[x].sum);return ;}
else if(l<=s[x].d[0]&&r>=s[x].d[0]&&ll<=s[x].d[1]&&rr>=s[x].d[1])ans=max(ans,s[x].v);
if(s[x].l&&l<=s[s[x].l].mx[0]&&ll<=s[s[x].l].mx[1])get(s[x].l,l,r,ll,rr);
if(s[x].r&&r>=s[s[x].r].mn[0]&&rr>=s[s[x].r].mn[1])get(s[x].r,l,r,ll,rr);
}
int main()
{
read(n),read(m);
for(rg int i=1;i<=n;i++)s[i].d[1]=f[i].d[1]=n+1;
for(rg int i=1,x;i<=n;i++)read(x),f[i].d[2]=w[x],f[i].id=i,f[i].d[0]=s[i].d[0]=i,f[w[x]].d[1]=s[w[x]].d[1]=i,w[x]=i,f[i].x=x;
rt[0]=(1+n)>>1;build(1,n,0,0,0,1);sort(f+1,f+n+1,cmp1);int now=1;id=n;
while(f[now].d[2]==0&&now<=n)change(rt[0],rt[0],f[now].d[0],f[now].d[1],f[now].x,1),now++;
for(rg int i=1;i<=n;i++)
{
rt[i]=rt[i-1];
while(f[now].d[2]==i&&now<=n)change(rt[i],rt[i],f[now].d[0],f[now].d[1],f[now].x,1),now++;
}
for(rg int i=1,x,y,l,r;i<=m;i++)
{
read(x),read(y),l=min((x+ans)%n+1,(y+ans)%n+1),r=max((x+ans)%n+1,(y+ans)%n+1);
ans=0,get(rt[l-1],l,r,r+1,n+1),printf("%d
",ans);
}
}
这个有意思呢,加个最优性剪枝就快了好几倍
AC代码:
#pragma GCC optimize(3)
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
void read(int &x) {
char ch; bool ok;
for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define rg register
#define pushup(x) s[x].sum=max(max(s[s[x].l].sum,s[s[x].r].sum),s[x].v)
const int maxn=1e5+1;
struct oo{int d[2],mn[2],mx[2],l,r,sum,v;}s[maxn*20];
struct o{int d[3],id,x;}f[maxn];
int n,m,rt[maxn],w[maxn],g,id,ans,d[maxn],c[maxn];
bool cmp(oo a,oo b){return a.d[g]<b.d[g];}
bool cmp1(o a,o b){return a.d[2]<b.d[2];}
inline void update(int x)
{
if(s[x].l)
{
s[x].mn[0]=min(s[s[x].l].mn[0],s[x].mn[0]);
s[x].mn[1]=min(s[s[x].l].mn[1],s[x].mn[1]);
s[x].mx[0]=max(s[s[x].l].mx[0],s[x].mx[0]);
s[x].mx[1]=max(s[s[x].l].mx[1],s[x].mx[1]);
}
if(s[x].r)
{
s[x].mn[0]=min(s[s[x].r].mn[0],s[x].mn[0]);
s[x].mn[1]=min(s[s[x].r].mn[1],s[x].mn[1]);
s[x].mx[0]=max(s[s[x].r].mx[0],s[x].mx[0]);
s[x].mx[1]=max(s[s[x].r].mx[1],s[x].mx[1]);
}
}
inline void build(int l,int r,int fa,int d,int v,int dep)
{
int mid=(l+r)>>1;g=d;
nth_element(s+l,s+mid,s+r+1,cmp);
s[mid].mn[0]=s[mid].mx[0]=s[mid].d[0];if(!v)s[fa].l=mid;else s[fa].r=mid;
s[mid].mn[1]=s[mid].mx[1]=s[mid].d[1];c[s[mid].d[0]]=c[s[fa].d[0]]|(v<<dep);
if(l!=mid)build(l,mid-1,mid,!d,0,dep+1);
if(r!=mid)build(mid+1,r,mid,!d,1,dep+1);
update(mid);return ;
}
inline void change(int x,int &k,int l,int r,int val,int dep)
{
k=++id,s[k]=s[x];
if(l==s[k].d[0]){s[k].v=val,s[k].sum=max(s[k].sum,val);return ;}
change((c[l]&(1<<(dep+1)))?s[x].r:s[x].l,(c[l]&(1<<(dep+1)))?s[k].r:s[k].l,l,r,val,dep+1);
pushup(k);
}
inline void get(int x,int l,int r,int ll,int rr)
{
if(l>s[x].mx[0]||r<s[x].mn[0]||ll>s[x].mx[1]||rr<s[x].mn[1]||ans>s[x].sum)return ;
if(l<=s[x].mn[0]&&r>=s[x].mx[0]&&ll<=s[x].mn[1]&&rr>=s[x].mx[1]){ans=max(ans,s[x].sum);return ;}
else if(l<=s[x].d[0]&&r>=s[x].d[0]&&ll<=s[x].d[1]&&rr>=s[x].d[1])ans=max(ans,s[x].v);
if(s[x].l&&l<=s[s[x].l].mx[0]&&ll<=s[s[x].l].mx[1])get(s[x].l,l,r,ll,rr);
if(s[x].r&&r>=s[s[x].r].mn[0]&&rr>=s[s[x].r].mn[1])get(s[x].r,l,r,ll,rr);
}
int main()
{
// freopen("1.in","r",stdin);
// freopen("my.out","w",stdout);
read(n),read(m);
for(rg int i=1;i<=n;i++)s[i].d[1]=f[i].d[1]=n+1;
for(rg int i=1,x;i<=n;i++)read(x),f[i].d[2]=w[x],f[i].id=i,f[i].d[0]=s[i].d[0]=i,f[w[x]].d[1]=s[w[x]].d[1]=i,w[x]=i,f[i].x=x;
rt[0]=(1+n)>>1;build(1,n,0,0,0,1);sort(f+1,f+n+1,cmp1);int now=1;id=n;
while(f[now].d[2]==0&&now<=n)change(rt[0],rt[0],f[now].d[0],f[now].d[1],f[now].x,1),now++;
for(rg int i=1;i<=n;i++)
{
rt[i]=rt[i-1];
while(f[now].d[2]==i&&now<=n)change(rt[i],rt[i],f[now].d[0],f[now].d[1],f[now].x,1),now++;
}
for(rg int i=1,x,y,l,r;i<=m;i++)
{
read(x),read(y),l=min((x+ans)%n+1,(y+ans)%n+1),r=max((x+ans)%n+1,(y+ans)%n+1);
ans=0,get(rt[l-1],l,r,r+1,n+1),printf("%d
",ans);
}
}