假设我们当前处理了询问(l1,r1),那么下个询问(l2,r2)需要操作的次数是|l1-l2|+|r1-r2|,其实就是曼哈顿距离,那么只需求出哈密尔顿路径即可确定操作序列,但是tsp不好求,则我们求出曼哈顿距离最小生成树,可知大小不超过tsp的两倍,莫队证出按此顺序操作复杂度是o(nsqrt(m))
曼哈顿距离最小生成树据说可以分成两块做,但是我实在觉得偏序关系处理起来有问题,所以还是扫了4遍,因为不想离散,所以用了一个奇怪的顺序排的
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> const int oo=1073741819; int tail[50005],next[1000000],sora[1000000],a[50005],c[50005],l[50005],r[50005],x[50005],y[50005],b[5][131072]; int ll[500000],rr[500000],w[500000],f[50005],u[500000]; int tim,n,m,m1,ss,tot,p,q,low,lim; long long ans,ans1[50005],ans2[50005],tmp; bool v[50005]; void origin() { for (m1=1;m1<=n+2;m1<<=1) ;m1++; for (int i=1;i<=m+1;i++) tail[i]=i;ss=m+1,tot=0; } inline int cmp1(const void *i,const void *j) { p=*(int *)i,q=*(int *)j; if (y[p]-x[p]!=y[q]-x[q]) return (y[q]-x[q])-(y[p]-x[p]); return x[p]-x[q]; } inline int cmp2(const void *i,const void *j) { p=*(int *)i,q=*(int *)j; if (y[p]+x[p]!=y[q]+x[q]) return (y[q]+x[q])-(y[p]+x[p]); return x[p]-x[q]; } inline int min(int e,int a,int b) { if (e<=2) return (x[a]+y[a]<=x[b]+y[b]) ? a : b; return (y[a]-x[a]<=y[b]-x[b]) ? a : b; } inline void change(int e,int x,int u) { for (x+=m1;x;x>>=1) { b[e][x]=min(e,b[e][x],u); if (b[e][x]!=u) return ; } } inline int ask(int e,int l,int r) { int sum=0; if (l>r) return 0; l+=m1-1,r+=m1+1; for (;!(1==(l^r));l>>=1,r>>=1) { if (0==(l&1)) sum=min(e,sum,b[e][l+1]); if (1==(r&1)) sum=min(e,sum,b[e][r-1]); } return sum; } void link(int p,int q) { if (!p || !q) return ; tot++; ll[tot]=p,rr[tot]=q,w[tot]=abs(x[p]-x[q])+abs(y[p]-y[q]); } void mysoul() { int i,xx; x[0]=0,y[0]=oo; qsort(u+1,m+1,sizeof(u[1]),cmp1);tim=1; for (i=1;i<=m+1;i++) { xx=ask(tim,x[u[i]],n); link(u[i],xx); change(tim,x[u[i]],u[i]); } tim=2; for (i=m+1;i>=1;i--) { xx=ask(tim,y[u[i]]+1,n); link(u[i],xx); change(tim,y[u[i]],u[i]); } qsort(u+1,m+1,sizeof(u[1]),cmp2);tim=3; for (i=1;i<=m+1;i++) { xx=ask(tim,0,x[u[i]]-1); link(u[i],xx); change(tim,x[u[i]],u[i]); } tim=4; for (i=m+1;i>=1;i--) { xx=ask(tim,y[u[i]],n); link(u[i],xx); change(tim,y[u[i]],u[i]); } } int find(int x) {if (f[x]!=x) f[x]=find(f[x]);return f[x];} int cmp3(const void *i,const void *j) {return w[*(int *)i]-w[*(int *)j];} long long gcd(long long a,long long b) { long long t; for (;a%b;) { t=a%b; a=b; b=t; } return b; } inline void del(int l,int r) {for (int i=l;i<=r;i++) c[a[i]]--,ans-=c[a[i]];} inline void add(int l,int r) {for (int i=l;i<=r;i++) ans+=c[a[i]],c[a[i]]++;} void dfs(int x) { int i,ne; if (r[x]>lim) add(lim+1,r[x]); if (l[x]<low) add(l[x],low-1); if (r[x]<lim) del(r[x]+1,lim); if (l[x]>low) del(low,l[x]-1); low=l[x],lim=r[x]; ans1[x]=ans,v[x]=1; for (i=x;next[i]!=0;) { i=next[i],ne=sora[i]; if (!v[ne]) dfs(ne); } } void link2(int x,int y) { ss++,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y; ss++,next[tail[y]]=ss,tail[y]=ss,sora[ss]=x; } void init() { int i,ls,rs; scanf("%d%d\n",&n,&m); origin(); for (i=1;i<=n;i++) scanf("%d",&a[i]); for (i=1;i<=m;i++) { scanf("%d%d\n",&l[i],&r[i]); x[i]=l[i],y[i]=r[i]+1; ans2[i]=((long long)r[i]-l[i]+1)*(r[i]-l[i])/2; u[i]=i; } l[m+1]=r[m+1]=x[m+1]=y[m+1]=0,u[m+1]=m+1; mysoul(); for (i=1;i<=tot;i++) u[i]=i; qsort(u+1,tot,sizeof(u[1]),cmp3); for (i=1;i<=m+1;i++) f[i]=i; for (i=1,tmp=m;i<=tot && tmp;i++) { ls=find(ll[u[i]]),rs=find(rr[u[i]]); if (ls!=rs) f[ls]=rs,tmp--,link2(ll[u[i]],rr[u[i]]); } low=lim=1,ans=0,c[a[1]]=1; dfs(m+1); for (i=1;i<=m;i++) { tmp=gcd(ans1[i],ans2[i]); printf("%I64d/%I64d\n",ans1[i]/tmp,ans2[i]/tmp); } } int main() { freopen("hose.in","r",stdin); freopen("hose.out","w",stdout); init(); return 0; }