1. 程式人生 > >2018.09.16 bzoj3757: 蘋果樹(樹上莫隊)

2018.09.16 bzoj3757: 蘋果樹(樹上莫隊)

傳送門 一道樹上莫隊。 先用跟bzoj1086一樣的方法給樹分塊。 分完之後就可以莫隊了。 但是兩個詢問之間如何轉移呢? 感覺很難受啊。 我們定義S(u,v)表示u->v這條路徑的點集,T(u,v)表示S(u,v) xor lca(u,v),同時我們令上一個詢問是S(predu,predv)。 對於T(u,v)有一個恆等式: T(u,v)=S(root,u) xor S(root,v) 因此有:

T(predu,predv)=S(root,predu) xor S(root,predv) 因此有: T(u,v) xor T(predu,predv)=S(root,u) xor S(root,v) xor S(root,predu) xor S(root,predv) 因此有: T(u,v)=T(predu,predv)
xor
T(predu,v) xor T(u,predv) 那麼更新就比較容易了。 程式碼:

#include<bits/stdc++.h>
#define N 100005
#define sig 24
using namespace std;
int n,m,rt,sum,ans[N],blo[N],dfn[N],dep[N],first[N],cnt,blos,top,fa[N][sig],mul[N],block,tot,stk[N],tim[N],col[N];
bool vis[N];
struct edge{int v,next
;}e[N<<1]; struct Q{int u,v,a,b,id;}q[N]; inline bool cmp(Q a,Q b){return blo[a.u]==blo[b.u]?dfn[a.v]<dfn[b.v]:blo[a.u]<blo[b.u];} inline void add(int u,int v){e[++cnt].v=v,e[cnt].next=first[u],first[u]=cnt;} inline void dfs(int p){ dfn[p]=++tot,dep[p]=dep[fa[p][0]]+1; int tmp=top; for(int i=1;i<sig;++i) if(dep[p]<mul[i])break; else fa[p][i]=fa[fa[p][i-1]][i-1]; for(int i=first[p];i;i=e[i].next){ int v=e[i].v; if(v==fa[p][0])continue; fa[v][0]=p,dfs(v); if(top-tmp>=block){ ++blos; while(top!=tmp)blo[stk[top--]]=blos; } } stk[++top]=p; } inline int lca(int x,int y){ if(dep[x]<dep[y])x^=y,y^=x,x^=y; int tmp=dep[x]-dep[y]; for(int i=0;i<sig;++i)if(tmp&(1<<i))x=fa[x][i]; if(x==y)return x; for(int i=sig-1;~i;--i)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; return fa[x][0]; } inline void update(int x){ if(vis[x]){ vis[x]=0,--tim[col[x]]; if(tim[col[x]]==0)--sum; } else{ vis[x]=1,++tim[col[x]]; if(tim[col[x]]==1)++sum; } } inline void reverse(int x,int y){ while(x!=y){ if(dep[x]<dep[y])x^=y,y^=x,x^=y; update(x),x=fa[x][0]; } } inline int read(){ int ans=0; char ch=getchar(); while(!isdigit(ch))ch=getchar(); while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar(); return ans; } int main(){ n=read(),m=read(),mul[0]=1,block=sqrt(n); for(int i=1;i<=n;++i)col[i]=read(); for(int i=1;i<=n;++i){ int u=read(),v=read(); if(!u||!v)rt=u+v; else add(u,v),add(v,u); } for(int i=1;i<sig;++i)mul[i]=mul[i-1]<<1; dfs(rt),++blos; while(top)blo[stk[top--]]=blos; for(int i=1;i<=m;++i){ q[i].u=read(),q[i].v=read(),q[i].a=read(),q[i].b=read(),q[i].id=i; if(d