bzoj2589【 Spoj 10707】 Count on a tree II
题目描述
给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v),你需要回答u xor lastans和v这两个节点间有多少种不同的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
输入格式
第一行两个整数N,M。
第二行有N个整数,其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
最后M行每行两个整数(u,v),表示一组询问。
数据范围是N<=40000 M<=100000 点权在int范围内
输出格式
M行,表示每个询问的答案。
-
题解
- 树上莫队;
- 如果不要求强制在线的话比较传统;
- 强制在线有点麻烦:
- 对树按深度分块,当一个点向下的深度超过$\sqrt{N}$就分一块;
- 这样分块保证了深度和块的数量在$O(\sqrt{N})$内,并且每一个块都是一颗子树;
- 预处理每个块的根对其他所有点的答案,这是$O(n\sqrt{N})$的时间和空间的;
- 考虑一个询问$u,v$如果在同一个块里则暴力查询;$O(\sqrt{N})$
- 否则假设$u$的根比$v$的根要深,否则交换;
- 利用预处理得到$(root_{u},v)$的答案$O(1)$,暴力查询$u$到$root_{u})$的颜色$O(\sqrt{N})$;
- 只需要查询某个颜色是否出现过;
- 可持久化块状链表记录$u$到原树的根链上的每个颜色出现的最大深度;$O(\sqrt{N})$
- 枚举的颜色没有出现过即查询颜色的最大深度一定小于$lca$的深度;
- 可持久化块状链表:
- 对颜色分块,记录每个历史版本每个块的起点;
- 插入的时候暴力复制上一个版本的起点,暴力新建一个修改位置的块并更新起点
- 可持久化块状链表:
-
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=40010,M=410; 4 int n,m,o=1,hd[N],F[N],num[N],tot,sub[N],dep[N],rt,c[N],ans; 5 int B,sum[M][N],bl[N],cnt,len[N],Rt[M],sta[N],top; 6 int min(int x,int y){return x<y?x:y;} 7 int max(int x,int y){return x>y?x:y;} 8 struct Edge{int v,nt;}E[N<<1]; 9 char gc(){ 10 static char*p1,*p2,s[1000000]; 11 if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin); 12 return(p1==p2)?EOF:*p1++; 13 } 14 int rd(){ 15 int x=0,f=1; char c=gc(); 16 while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();} 17 while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc(); 18 return x*f; 19 } 20 void adde(int u,int v){ 21 E[o]=(Edge){v,hd[u]};hd[u]=o++; 22 E[o]=(Edge){u,hd[v]};hd[v]=o++; 23 } 24 namespace Block{ 25 int l[N][M],a[N*M],Cnt,bl[N],B,st[M],ed[M],sz; 26 void init(){ 27 B=sqrt(tot)+1; 28 for(int i=1;i<=tot;++i)bl[i]=(i-1)/B+1,a[i]=-1; 29 sz=bl[tot]; 30 for(int i=1;i<=sz;++i){ 31 l[0][i]=st[i]=ed[i-1]+1; 32 ed[i]=ed[i-1]+B; 33 } 34 ed[sz]=Cnt=tot; 35 } 36 int que(int u,int x){return a[l[u][bl[x]]+(x-1)%B];} 37 void ins(int u,int x){ 38 for(int i=1;i<=sz;++i)l[u][i]=l[F[u]][i]; 39 int len=ed[bl[x]]-st[bl[x]],tmp=l[u][bl[x]],pre=Cnt; 40 for(int i=0;i<=len;++i)a[++Cnt]=a[tmp+i]; 41 a[pre+1+(x-1)%B]=dep[u]; 42 l[u][bl[x]]=pre+1; 43 } 44 } 45 void upd(int x,int y){ 46 if((num[x]==0)^(num[x]+y==0))tot+=y; 47 num[x]+=y; 48 } 49 void dfs1(int u,int fa){ 50 upd(c[u],1); 51 sum[cnt][u]=tot; 52 for(int i=hd[u];i;i=E[i].nt)if(E[i].v!=fa)dfs1(E[i].v,u); 53 upd(c[u],-1); 54 } 55 void dfs(int u,int fa){ 56 int x=c[u]; 57 F[u]=fa; 58 Block::ins(u,x); 59 sta[++top]=u; 60 for(int i=hd[u];i;i=E[i].nt){ 61 int v=E[i].v; 62 if(v==fa)continue; 63 dep[v]=dep[u]+1; 64 dfs(v,u); 65 len[u]=max(len[v]+1,len[u]); 66 } 67 if(len[u]>=B||u==1){ 68 len[u]=-1; 69 Rt[++cnt]=u; 70 int v;do{ 71 bl[v=sta[top--]]=cnt; 72 }while(v!=u); 73 dfs1(u,0); 74 } 75 } 76 namespace LCA{ 77 int son[N],tp[N],sz[N],F[N]; 78 void dfs1(int u,int fa){ 79 sz[u]=1;son[u]=0;F[u]=fa; 80 for(int i=hd[u];i;i=E[i].nt){ 81 int v=E[i].v; 82 if(v==fa)continue; 83 dfs1(v,u); 84 sz[u]+=sz[v]; 85 if(sz[v]>sz[son[u]])son[u]=v; 86 } 87 } 88 void dfs2(int u,int T){ 89 tp[u]=T; 90 if(son[u])dfs2(son[u],T); 91 for(int i=hd[u];i;i=E[i].nt){ 92 int v=E[i].v; 93 if(v==F[u]||v==son[u])continue; 94 dfs2(v,v); 95 } 96 } 97 int ask(int u,int v){ 98 int tu=tp[u],tv=tp[v]; 99 while(tu!=tv){ 100 if(dep[tu]<dep[tv])v=F[tv],tv=tp[v]; 101 else u=F[tu],tu=tp[u]; 102 } 103 return dep[u]<dep[v]?u:v; 104 } 105 void init(){dfs1(1,0);dfs2(1,1);} 106 } 107 void query1(int u,int v){ 108 int x=Rt[bl[u]],y=Rt[bl[v]],dz=dep[LCA::ask(u,v)]; 109 if(dep[x]<dep[y])swap(x,y),swap(u,v); 110 ans=sum[bl[u]][v]; 111 for(int w=u;w!=x;w=F[w]){ 112 int d = max(Block::que(x,c[w]),Block::que(v,c[w])); 113 if(!num[c[w]]&&d<dz)num[c[w]]=1,ans++; 114 } 115 for(int w=u;w!=x;w=F[w])num[c[w]]=0; 116 printf("%d\n",ans); 117 } 118 void query2(int u,int v){ 119 int dz=dep[LCA::ask(u,v)]; 120 ans=0; 121 for(int w=u;dep[w]>=dz;w=F[w])if(!(num[c[w]]++))ans++; 122 for(int w=v;dep[w]>=dz;w=F[w])if(!(num[c[w]]++))ans++; 123 for(int w=u;dep[w]>=dz;w=F[w])num[c[w]]=0; 124 for(int w=v;dep[w]>=dz;w=F[w])num[c[w]]=0; 125 printf("%d\n",ans); 126 } 127 int find(int x){ 128 int l=1,r=tot,mid; 129 while(l<r){ 130 if(x<=sub[mid=l+r>>1])r=mid; 131 else l=mid+1; 132 } 133 return l; 134 } 135 int main(){ 136 #ifndef ONLINE_JUDGE 137 freopen("bzoj2589.in","r",stdin); 138 freopen("bzoj2589.out","w",stdout); 139 #endif 140 n=rd();m=rd(); 141 B=sqrt(n)+1; 142 for(int i=1,x;i<=n;++i)c[i]=sub[i]=rd(); 143 for(int i=1,u,v;i<n;++i)adde(rd(),rd()); 144 tot=n;sort(sub+1,sub+tot+1); 145 tot=unique(sub+1,sub+tot+1)-sub-1; 146 for(int i=1;i<=n;++i)c[i]=lower_bound(sub+1,sub+tot+1,c[i])-sub; 147 Block::init(); 148 dep[0]=-1; 149 tot=0;dfs(1,0); 150 LCA::init(); 151 for(int i=1,x,y;i<=m;++i){ 152 x=rd()^ans,y=rd(); 153 if(bl[x]!=bl[y])query1(x,y); 154 else query2(x,y); 155 } 156 return 0; 157 }