[bzoj2589]Spoj 10707 Count on a tree II
来自FallDream的博客,未经允许,请勿转载,谢谢。
给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v),你需要回答u xor lastans和v这两个节点间有多少种不同的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
n<=40000 m<=100000
写了强制在线的树上莫队...
把树分成$n^{\frac{1}{3}}$块,每个块定一个点作为中心,预处理两两中心之间的答案。然后每次询问找到那两个点的中心,像莫队那样暴力移动。显然每次最多移动$n^{\frac{2}{3}}$次,所以复杂度$m*n^{\frac{2}{3}}$
这道题有2s,然而交上去T了 bzoj神级评测机 本机测根本T不了啊
随便搜搜题解,搜到了PoPoQQQ大爷的博文,发现大爷也T了....瞬间感觉自己写的没救了,绝望
卡常数狗我也*** 总有一天我也会用莫队卡过这道题的
然后去搜了一个靠谱做法
先分成大小为根号n的块,然后用可持久化块状数组存下每个点到根的路径上所有权值出现的最大深度,预处理好每个块顶到所有点的答案。
然后每个询问,块内的暴力查,如果在不同块,选择块顶的深度较大的点,找到它到另一个点的答案。
这样以后只要处理这个点到块顶的那条链就行了,由于我们已经预处理了每种权值的最大深度,所以我们可以判断每种权值是否已经出现了。
复杂度$O(n^{\frac{3}{2}})$
血的教训,倍增一定要把小的写前面,我tm也就T了一个号吧。
------
莫队
#include<iostream> #include<cstdio> #include<algorithm> #include<vector> #define R register #define MN 40000 #define MK 38 #define MD 15 #define getchar() ((S==T&&(T=((S=B)+fread(B,1,1<<15,stdin)),S==T))?0:(*S++)) char B[1<<15],*S=B,*T=B; using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int head[MN+5],cnt=0,n,m,f[MK+2][MK+2][MN+1],l[MN+5],size,fa[MN+5][MD+2],dep[MN+5]; int num=0,tot=1,bel[MN+5],a[MN+5],kind[MK+1][MK+1],last=0,cap[MK+2]; bool b[MK+2][MK+2][MN+1]; vector<int> v[MN+1]; struct edge{int to,next;}e[MN*2+5]; inline void ins(int f,int t) { e[++cnt]=(edge){t,head[f]};head[f]=cnt; e[++cnt]=(edge){f,head[t]};head[t]=cnt; } void dfs(int x,int f) { fa[x][0]=f; for(int i=head[x];i;i=e[i].next) if(e[i].to!=f) { int y=e[i].to; dep[y]=dep[x]+1;dfs(y,x); for(int j=0;j<v[y].size();j++) v[x].push_back(v[y][j]); if(v[x].size()>=size) { ++num;cap[num]=x; for(int j=v[x].size()-1;j>=0;--j) bel[v[x][j]]=num; for(;v[x].size();) v[x].pop_back(); } } v[x].push_back(x); } inline void update(int i,int j,int x) { if(!b[i][j][x]) { b[i][j][x]=1; if(++f[i][j][a[x]]==1) ++kind[i][j]; } else { b[i][j][x]=0; if(!--f[i][j][a[x]]) --kind[i][j]; } } void update_chain(int i,int j,int x,int y) { if(dep[x]<dep[y]) swap(x,y); while(dep[x]>dep[y]) { update(i,j,x); x=fa[x][0]; } while(x!=y) { update(i,j,x);update(i,j,y); x=fa[x][0];y=fa[y][0]; } } int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); for(int k=dep[x]-dep[y],j=0;k;k>>=1,j++) if(k&1) x=fa[x][j]; if(x==y) return x; for(int i=MD;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int main() { // freopen("sb.in","r",stdin); // freopen("sb2.out","w",stdout); n=read();m=read();size=max(1,(n+MK-1)/MK); for(R int i=1;i<=n;i++) a[i]=l[i]=read(); sort(l+1,l+n+1); for(R int i=2;i<=n;i++) if(l[i]!=l[i-1]) l[++tot]=l[i]; for(R int i=1;i<=n;i++) a[i]=lower_bound(l+1,l+tot+1,a[i])-l; for(R int i=1;i<n;i++) ins(read(),read()); dfs(1,0); if(v[1].size()) { cap[++num]=1; for(R int i=0;i<v[1].size();i++) bel[v[1][i]]=num; } for(R int i=1;i<=MD;i++) for(R int j=1;j<=n;j++) fa[j][i]=fa[fa[j][i-1]][i-1]; for(R int i=1;i<=num;i++) for(R int j=i;j<=num;j++) { int x=cap[i],y=cap[j]; update_chain(i,j,x,y); } for(R int i=1;i<=m;i++) { int x=read(),y=read(),a=cap[bel[x]],b=cap[bel[y]],z=lca(x,y),c=min(bel[x],bel[y]),d=max(bel[x],bel[y]); update_chain(c,d,a,x); update_chain(c,d,b,y); update(c,d,z); printf("%d\n",last=kind[c][d]); update_chain(c,d,a,x); update_chain(c,d,b,y); update(c,d,z); } return 0; }
靠谱做法
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #define MN 40000 #define MK 200 #define MD 15 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int n,m,ans[MK+2][MN+2],a[MN+5],l[MN+5],head[MN+5],cnt=0,size,p[MN+5][MK+1],kind=0,P[MN+5],B[MN+5]; int arrnum=0,fa[MD+2][MN+2],dep[MN+5],bel[MN+5],num=0,rt[MK+5],f[MN+5],last=0,q[MN+5],top; struct edge{int to,next;}e[MN*2+5]; struct Array { int num[MK+1]; int operator[](int x){return p[num[B[x]]][P[x]];} void insert(const Array&pre,int x,int dep) { int block=B[x],t=P[x]; memcpy(num,pre.num,sizeof(num)); memcpy(p[++arrnum],p[num[block]],sizeof(p[0])); p[arrnum][t]=dep;num[block]=arrnum; } }s[MN+5]; inline void ins(int f,int t) { e[++cnt]=(edge){t,head[f]};head[f]=cnt; e[++cnt]=(edge){f,head[t]};head[t]=cnt; } int init(int x,int f) { fa[0][x]=f;s[x].insert(s[f],a[x],dep[x]); q[++top]=x;int mxdp=dep[x],beg=top; for(int i=head[x];i;i=e[i].next) if(e[i].to!=f) { int y=e[i].to;dep[y]=dep[x]+1; mxdp=max(mxdp,init(y,x)); } if(mxdp-dep[x]>=size||beg==1) { rt[++num]=x; for(int i=beg;i<=top;i++) bel[q[i]]=num; top=beg-1;return dep[x]-1; } else return mxdp; } void getans(int x,int fat,int from) { if(++f[a[x]]==1) ++kind;ans[from][x]=kind; for(int i=head[x];i;i=e[i].next) if(e[i].to!=fat) getans(e[i].to,x,from); if(!--f[a[x]]) --kind; } int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); for(int k=dep[x]-dep[y],j=0;k;k>>=1,j++) if(k&1) x=fa[j][x]; if(x==y) return x; for(int i=MD;i>=0;i--) if(fa[i][x]!=fa[i][y]) x=fa[i][x],y=fa[i][y]; return fa[0][x]; } int solve_force(int x,int y) { for(top=kind=0;x!=y;x=fa[0][x]) { if(dep[x]<dep[y]) swap(x,y); if(!f[a[x]]++) ++kind,q[++top]=a[x]; } int ans=kind+(!f[a[x]]); for(;top;--top) f[q[top]]=0; return ans; } int solve_block(int x,int y) { if(dep[rt[bel[x]]]<dep[rt[bel[y]]]) swap(x,y); int sum=ans[bel[x]][y]; int z=rt[bel[x]],d=dep[lca(x,y)]; for(;x!=z;x=fa[0][x]) { if(!f[a[x]]&&s[z][a[x]]<d&&s[y][a[x]]<d) f[q[++top]=a[x]]=1,++sum; } for(;top;--top) f[q[top]]=0; return sum; } int main() { n=read();m=read();size=sqrt(n); for(int i=1;i<=n;i++) B[i]=(i-1)/size+1,P[i]=i%size; for(int i=1;i<=n;i++) l[i]=a[i]=read(); sort(l+1,l+n+1);int tot=1; for(int i=2;i<=n;i++) if(l[i]!=l[i-1])l[++tot]=l[i]; for(int i=1;i<=n;i++) a[i]=lower_bound(l+1,l+tot+1,a[i])-l; for(int i=1;i<n;i++) ins(read(),read()); dep[1]=1;init(1,0); for(int i=1;i<=num;i++) getans(rt[i],0,i); for(int j=1;j<=MD;j++) for(int i=1;i<=n;i++) fa[j][i]=fa[j-1][fa[j-1][i]]; for(int i=1;i<=m;i++) { int x=read()^last,y=read(); if(bel[x]==bel[y]) printf("%d\n",last=solve_force(x,y)); else printf("%d\n",last=solve_block(x,y)); } return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream