这题之前度娘上没有CDQ分治做法,gerwYY出来以后写了一个。不过要sort3遍,常数很大。
gerw说可以类似划分树的思想优化复杂度,但是蒟蒻目前不会划分树(会了主席树就懒得去弄了)。
嗯 将memset改成手动clear会快很多。
还有就是第一维相同的情况,划分为两个不存在第一维相同的两个区间即可。
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<iostream> using namespace std; const int Maxn=100000 + 10; int C[Maxn*2],ans=0,A,P,n=0,h[Maxn],tot=0; struct Node{ int a,b,c,ans; void init(int x,int y,int z){ if(x>y)swap(x,y); if(x>z)swap(x,z); if(y>z)swap(y,z); a=x,b=y,h[++tot]=c=z; ans=1; } }p[Maxn],q[Maxn]; inline void Add(int x,const int&y){ for(;0<x&&x<=n;x+=x&-x)C[x]=max(C[x],y); } inline void HashIt(int&x){ x=lower_bound(h+1,h+n+1,x)-h; } inline int Query(int x){ int ret=0; for(;0<x&&x<=n;x-=x&-x)ret=max(ret,C[x]); return ret; } inline void Clear(int x) { for(;x<=n;x+=x&-x)C[x]=0; } inline bool cmpa(const Node&x,const Node&y){ if(x.a!=y.a)return x.a<y.a; if(x.b!=y.b)return x.b<y.b; return x.c<y.c; } inline bool cmpb(const Node&x,const Node&y){ if(x.b!=y.b)return x.b<y.b; return x.c<y.c; } void init(){ scanf("%d%d%d",&A,&P,&n); for(int a,b,c,t=1,i=1;i<=n;i++){ a=(t=(long long)A*t%P); b=(t=(long long)A*t%P); c=(t=(long long)A*t%P); p[i].init(a,b,c); } sort(p+1,p+n+1,cmpa); sort(h+1,h+n+1); for(int i=1;i<=n;i++)HashIt(p[i].c); } void CDQ(int l,int r){ if(l==r)return; int mid=-1,L=(l+r)>>1,R=L+1; while(l<=L || R<=r){ if(l<=L && p[L].a!=p[L+1].a){mid=L;break;} if(R<=r && p[R].a!=p[R-1].a){mid=R-1;break;} L--,R++; } if(mid==-1)return; CDQ(l,mid); sort(p+l,p+mid+1,cmpb); sort(p+mid+1,p+r+1,cmpb); int i=l; for(int j=mid+1;j<=r;j++){ for(;i<=mid && p[i].b<p[j].b;i++)Add(p[i].c,p[i].ans); p[j].ans=max(p[j].ans,Query(p[j].c-1)+1); } for(int j=l;j<=i;j++)Clear(p[j].c); sort(p+mid+1,p+r+1,cmpa); CDQ(mid+1,r); } int main(){ init(); CDQ(1,n); for(int i=1;i<=n;i++) if(p[i].ans>ans)ans=p[i].ans; printf("%d\n",ans); return 0; }
时间: 2024-11-18 21:20:26