[HNOI2016] 树 题解
[HNOI2016] 树 题解
题意简述
给定一棵 \(n\) 个点的模版树,然后 \(m\) 次地将它的某棵子树复制到另一棵大树上,然后 \(Q\) 次查询结点间距。
分析
比较简单,只是实现较烦琐。
\(30\%\)
\(n,m \le 500\),尝试把模版树的每棵子树都预处理出来,复制时暴力建树,然后倍增求 LCA 即可。复杂度 \(O((Q+nm)\log_2{nm})\)。
\(60\%\)
\(n\le 3000\),依旧是把模版树的每棵子树都预处理出来,但是要把每个复制的子树当成一个大节点,然后求 LCA 时先在大节点上倍增,再转回原树节点上,再转回来,复杂度 \(O(n^2+(Q+m)(\log_2{n}+\log_2{m}))\) 之类的。
//#define Plus_Cat ""
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f
#define ll int
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define FOR(i,a,b) for(int i(a); i<=(int)(b); ++i)
#define DOR(i,a,b) for(int i(a); i>=(int)(b); --i)
#define EDGE(g,i,x,y) for(int i(g.h[x]),y(g[i].v); ~i; y=g[i=g[i].nxt].v)
using namespace std;
constexpr int N(1e5+10),M(250500+10);
namespace IOEcat {
#define isD(c) ('0'<=(c)&&(c)<='9')
#define DE(...) E(#__VA_ARGS__,__VA_ARGS__)
struct Icat {
char getc() {
return getchar();
}
template<class T>void operator ()(T &x) {
static bool sign(0);
static char ch(0);
sign=0,x=0;
while(ch=getc(),!isD(ch))if(ch=='-')sign=1;
do x=(x<<1)+(x<<3)+(ch^48);
while(ch=getc(),isD(ch));
if(sign)x=-x;
}
template<class T,class...Types>void operator ()(T &x,Types&...args) {
return (*this)(x),(*this)(args...);
}
} I;
struct Ocat {
void putc(char c) {
putchar(c);
}
template<class T>void operator ()(T x,const char lst='\n') {
static int top(0);
static char st[100];
if(x<0)x=-x,putc('-');
do st[++top]=(x%10)^48,x/=10;
while(x);
while(top)putc(st[top--]);
putc(lst);
}
template<class T,class...Types>void operator ()(const T x,const char lst='\n',const Types...args) {
return (*this)(x,lst),(*this)(args...);
}
} O;
struct Ecat {
template<class T>void operator ()(const char *fmt,const T x) {
cerr<<fmt<<':'<<x<<'.'<<endl;
}
template<class T,class...Types>void operator ()(const char *fmt,const T x,const Types...args) {
while(*fmt^',')cerr<<*fmt++;
return cerr<<':'<<x<<" ,",(*this)(++fmt,args...);
}
} E;
} using namespace IOEcat;
int n,m,Q,idx;
int dl[N],dr[N],fa[M],dep[M],dfn[N],siz[N],son[N],top[N];
struct CFS {
int tot,h[M];
struct edge {
int v,nxt;
edge(int v=0,int nxt=-1):v(v),nxt(nxt) {}
} e[M<<1];
edge &operator [](int i) {
return e[i];
}
void Init() {
tot=-1,RCL(h,-1,h,1);
}
void att(int u,int v) {
e[++tot]=edge(v,h[u]),h[u]=tot;
}
void con(int u,int v) {
att(u,v),att(v,u);
}
} g;
void dfs0(int u) {
dep[u]=dep[fa[u]]+1,siz[u]=1,son[u]=0;
EDGE(g,i,u,v)if(v^fa[u])fa[v]=u,dfs0(v),siz[u]+=siz[v],son[u]=(siz[v]>siz[son[u]]?v:son[u]);
}
void dfs1(int u) {
dfn[dl[u]=++idx]=u;
if(son[u])top[son[u]]=top[u],dfs1(son[u]);
EDGE(g,i,u,v)if(v!=fa[u]&&v!=son[u])top[v]=v,dfs1(v);
dr[u]=idx;
}
int lca(int u,int v) {
for(; top[u]^top[v]; v=fa[top[v]]) {
if(dep[top[u]]>dep[top[v]])swap(u,v);
}
return dep[u]<dep[v]?u:v;
}
int dis(int u,int v) {
return (dep[u]+dep[v])-(dep[lca(u,v)]<<1);
}
namespace Subtask1 {
constexpr int N(5e2+10),lN(17),lV(lN+1);
bool vis[N];
int idx[N];
int fa[M][lV];
vector<int> Fa[N];
bool Check() {
return n<=500&&m<=500;
}
template<const bool ty>void Rebuild(int u) {
fa[u][0]=::fa[u];
FOR(i,1,lN)fa[u][i]=fa[fa[u][i-1]][i-1];
EDGE(g,i,u,v)if(v!=fa[u][0]&&v!=son[u])Rebuild<0>(v);
if(son[u])Rebuild<1>(son[u]);
EDGE(g,i,u,v)if(v!=fa[u][0]&&v!=son[u])FOR(j,dl[v],dr[v])vis[dfn[j]]=1;
vis[u]=1;
Fa[u]=vector<int>(siz[u]+1,0);
int tot(0);
FOR(i,1,n)idx[i]=(vis[i]?++tot:0);
FOR(i,1,n)if(vis[i])Fa[u][idx[i]]=idx[fa[i][0]];
if(!ty)FOR(i,dl[u],dr[u])vis[dfn[i]]=0;
}
void Update(int u) {
dep[u]=dep[fa[u][0]]+1;
FOR(i,1,lN)fa[u][i]=fa[fa[u][i-1]][i-1];
EDGE(g,i,u,v)if(v^fa[u][0])Update(v);
}
int lca(int u,int v) {
if(dep[u]>dep[v])swap(u,v);
DOR(i,lN,0)if((dep[v]-dep[u])&1<<i)v=fa[v][i];
if(u==v)return u;
DOR(i,lN,0)if(fa[u][i]^fa[v][i])u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
int dis(int u,int v) {
return (dep[u]+dep[v])-(dep[lca(u,v)]<<1);
}
int Cmain() {
Rebuild<0>(1);
FOR(i,1,m) {
int u,pa,rt(0);
I(u,pa);
FOR(j,1,Fa[u].size()-1)g.att(fa[n+j][0]=(Fa[u][j]?n+Fa[u][j]:(rt=n+j,pa)),n+j);
Update(rt),n+=siz[u];
}
FOR(i,1,Q) {
int u,v;
I(u,v),O(dis(u,v),'\n');
}
return 0;
}
}
namespace Subtask2 {
constexpr int N(3e3+10),M(1e5+10),lN(16),lV(lN+1);
bool vis[N];
int tot;
int rt[M],ty[M],rdep[M],mi[N],xFa[M];
int Fa[M][lV],dFa[M][lV];
vector<int> Dep[N],Idx[N];
bool Check() {
return n<=3000;
}
template<const bool ty>void Rebuild(int u) {
EDGE(g,i,u,v)if(v!=fa[u]&&v!=son[u])Rebuild<0>(v);
if(son[u])Rebuild<1>(son[u]);
EDGE(g,i,u,v)if(v!=fa[u]&&v!=son[u])FOR(j,dl[v],dr[v])vis[dfn[j]]=1;
vis[u]=1;
int tot(0);
Dep[u]=vector<int>(siz[u]+1,0),Idx[u]=vector<int>(siz[u]+1,0);
FOR(i,1,n)if(vis[i])Dep[u][++tot]=dep[i]-dep[u]+1,Idx[u][tot]=i,mi[u]=(i==u?tot:mi[u]);
if(!ty)FOR(i,dl[u],dr[u])vis[dfn[i]]=0;
}
int Root(int idx) {
return upper_bound(rt+1,rt+tot+1,idx)-rt-1;
}
int Dis(int u,int v) {
int x(Root(u)),y(Root(v)),ans(0);
if(x==y)return dis(Idx[ty[x]][u-rt[x]+1],Idx[ty[y]][v-rt[y]+1]);
if(rdep[x]>rdep[y])swap(u,v),swap(x,y);
if(rdep[x]<rdep[y])ans+=Dep[ty[y]][v-rt[y]+1]-1,v=rt[y]+mi[ty[y]]-1;
DOR(i,lN,0)if(rdep[Fa[y][i]]>rdep[x])ans+=dFa[y][i],y=Fa[y][i],v=rt[y]+mi[ty[y]]-1;
if(Fa[y][0]==x)return v=xFa[y],y=Fa[y][0],ans+1+dis(Idx[ty[x]][u-rt[x]+1],Idx[ty[y]][v-rt[y]+1]);
if(rdep[y]>rdep[x])v=xFa[y],y=Fa[y][0],++ans;
ans+=Dep[ty[y]][v-rt[y]+1]-1,v=rt[y]+mi[ty[y]]-1,ans+=Dep[ty[x]][u-rt[x]+1]-1,u=rt[x]+mi[ty[x]]-1;
DOR(i,lN,0)if(Fa[x][i]^Fa[y][i])
ans+=dFa[x][i]+dFa[y][i],x=Fa[x][i],y=Fa[y][i],u=rt[x]+mi[ty[x]]-1,v=rt[y]+mi[ty[y]]-1;
u=xFa[x],v=xFa[y],x=Fa[x][0],y=Fa[y][0];
return ans+2+dis(Idx[ty[x]][u-rt[x]+1],Idx[ty[y]][v-rt[y]+1]);
}
int Cmain() {
rt[tot=1]=ty[1]=rdep[1]=1,Rebuild<0>(1);
FOR(i,1,m) {
int u,pa,Pa;
I(u,pa),Pa=Root(pa),rt[++tot]=n+1,n+=siz[ty[tot]=u],rdep[tot]=rdep[Pa]+1,xFa[tot]=pa;
Fa[tot][0]=Pa,dFa[tot][0]=Dep[ty[Pa]][pa-rt[Pa]+1];
FOR(j,1,lN)Fa[tot][j]=Fa[Fa[tot][j-1]][j-1];
FOR(j,1,lN)dFa[tot][j]=dFa[tot][j-1]+dFa[Fa[tot][j-1]][j-1];
}
FOR(i,1,Q) {
int u,v;
I(u,v),O(Dis(u,v),'\n');
}
return 0;
}
}
int main() {
#ifdef Plus_Cat
freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
I(n,m,Q),g.Init();
FOR(i,2,n) {
int u,v;
I(u,v),g.con(u,v);
}
dfs0(1),top[1]=1,dfs1(1);
if(Subtask1::Check())return Subtask1::Cmain();
if(Subtask2::Check())return Subtask2::Cmain();
return 0;
}
\(100\%\)
考虑把预处理去掉,用数据结构代替,可以选择可持久化线段树,转化为区间第 \(k\) 小问题。
复杂度 \(O((Q+n+m)(\log_2{n}+\log_2{m}))\) 之类。
//#define Plus_Cat ""
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f
#define ll long long
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define FOR(i,a,b) for(int i(a); i<=(int)(b); ++i)
#define DOR(i,a,b) for(int i(a); i>=(int)(b); --i)
#define EDGE(g,i,x,y) for(int i(g.h[x]),y(g[i].v); ~i; y=g[i=g[i].nxt].v)
using namespace std;
constexpr int N(1e5+10),lN(16),lV(lN+1);
namespace IOEcat {
#define isD(c) ('0'<=(c)&&(c)<='9')
#define DE(...) E(#__VA_ARGS__,__VA_ARGS__)
struct Icat {
char getc() {
return getchar();
}
template<class T>void operator ()(T &x) {
static bool sign(0);
static char ch(0);
sign=0,x=0;
while(ch=getc(),!isD(ch))if(ch=='-')sign=1;
do x=(x<<1)+(x<<3)+(ch^48);
while(ch=getc(),isD(ch));
if(sign)x=-x;
}
template<class T,class...Types>void operator ()(T &x,Types&...args) {
return (*this)(x),(*this)(args...);
}
} I;
struct Ocat {
void putc(char c) {
putchar(c);
}
template<class T>void operator ()(T x,const char lst='\n') {
static int top(0);
static char st[100];
if(x<0)x=-x,putc('-');
do st[++top]=(x%10)^48,x/=10;
while(x);
while(top)putc(st[top--]);
putc(lst);
}
template<class T,class...Types>void operator ()(const T x,const char lst='\n',const Types...args) {
return (*this)(x,lst),(*this)(args...);
}
} O;
struct Ecat {
template<class T>void operator ()(const char *fmt,const T x) {
cerr<<fmt<<':'<<x<<'.'<<endl;
}
template<class T,class...Types>void operator ()(const char *fmt,const T x,const Types...args) {
while(*fmt^',')cerr<<*fmt++;
return cerr<<':'<<x<<" ,",(*this)(++fmt,args...);
}
} E;
} using namespace IOEcat;
int n,m,Q,idx,tot;
int dl[N],dr[N],fa[N],dep[N],dfn[N],siz[N],son[N],top[N];
ll cnt;
struct CFS {
int tot,h[N];
struct edge {
int v,nxt;
edge(int v=0,int nxt=-1):v(v),nxt(nxt) {}
} e[N<<1];
edge &operator [](int i) {
return e[i];
}
void Init() {
tot=-1,RCL(h,-1,h,1);
}
void att(int u,int v) {
e[++tot]=edge(v,h[u]),h[u]=tot;
}
void con(int u,int v) {
att(u,v),att(v,u);
}
} g;
struct PSEG {
int tot,rt[N];
struct node {
int ls,rs,sum;
node(int ls=0,int rs=0,int sum=0):ls(ls),rs(rs),sum(sum) {}
} tr[N*lV];
int &operator [](int i) {
return rt[i];
}
#define ls(p) (tr[p].ls)
#define rs(p) (tr[p].rs)
#define mid ((l+r)>>1)
void Plus(int x,int &p,int q,int l=1,int r=n) {
tr[p=++tot]=tr[q],++tr[p].sum;
if(l==r)return;
return x<=mid?Plus(x,ls(p),ls(q),l,mid):Plus(x,rs(p),rs(q),mid+1,r);
}
int BS(int k,int p,int q,int l=1,int r=n) {
if(l==r)return l;
if(k<=tr[ls(q)].sum-tr[ls(p)].sum)return BS(k,ls(p),ls(q),l,mid);
return BS(k-(tr[ls(q)].sum-tr[ls(p)].sum),rs(p),rs(q),mid+1,r);
}
int Sum(int L,int R,int p,int q,int l=1,int r=n) {
if(L<=l&&r<=R)return tr[q].sum-tr[p].sum;
if(R<=mid)return Sum(L,R,ls(p),ls(q),l,mid);
if(mid<L)return Sum(L,R,rs(p),rs(q),mid+1,r);
return Sum(L,R,ls(p),ls(q),l,mid)+Sum(L,R,rs(p),rs(q),mid+1,r);
}
#undef ls
#undef rs
#undef mid
} seg;
void dfs0(int u) {
dep[u]=dep[fa[u]]+1,siz[u]=1,son[u]=0;
EDGE(g,i,u,v)if(v^fa[u])fa[v]=u,dfs0(v),siz[u]+=siz[v],son[u]=(siz[v]>siz[son[u]]?v:son[u]);
}
void dfs1(int u) {
dfn[dl[u]=++idx]=u;
if(son[u])top[son[u]]=top[u],dfs1(son[u]);
EDGE(g,i,u,v)if(v!=fa[u]&&v!=son[u])top[v]=v,dfs1(v);
dr[u]=idx;
}
int lca(int u,int v) {
for(; top[u]^top[v]; v=fa[top[v]]) {
if(dep[top[u]]>dep[top[v]])swap(u,v);
}
return dep[u]<dep[v]?u:v;
}
struct Tree {
int ty,Depth;
ll pa,rt,mi,depth;
int fa[lV];
int &operator [](int i) {
return fa[i];
}
int idx(ll k) {
return seg.BS(k-mi+1,seg[dl[ty]-1],seg[dr[ty]]);
}
ll rev(int k) {
return mi+seg.Sum(1,k,seg[dl[ty]-1],seg[dr[ty]])-1;
}
ll Dep(ll k) {
return depth+(dep[idx(k)]-dep[ty]+1)-1;
}
} a[N];
int Idx(ll k) {
int ans(0);
for(int l(1),r(tot),mid((l+r)>>1); l<=r; mid=(l+r)>>1)a[mid].mi<=k?ans=mid,l=mid+1:r=mid-1;
return ans;
}
void Build(int ty,ll pa,Tree &A) {
A.ty=ty,A.pa=pa,A.rt=cnt+seg.Sum(1,ty,seg[dl[ty]-1],seg[dr[ty]]),A.mi=cnt+1,cnt+=siz[ty];
A.depth=a[A[0]=Idx(pa)].Dep(pa)+1,A.Depth=a[A[0]].Depth+1;
FOR(i,1,lN)A[i]=a[A[i-1]][i-1];
}
ll Lca(ll u,ll v) {
int x(Idx(u)),y(Idx(v));
if(x==y)return a[x].rev(lca(a[x].idx(u),a[y].idx(v)));
if(a[x].Depth>a[y].Depth)swap(x,y),swap(u,v);
DOR(i,lN,0)if(a[a[y][i]].Depth>a[x].Depth)v=a[y=a[y][i]].rt;
if(a[y][0]==x)return v=a[y].pa,y=a[y][0],a[x].rev(lca(a[x].idx(u),a[y].idx(v)));
if(a[y].Depth>a[x].Depth)v=a[y=a[y][0]].rt;
DOR(i,lN,0)if(a[x][i]^a[y][i])x=a[x][i],y=a[y][i];
u=a[x].pa,v=a[y].pa,x=a[x][0],y=a[y][0];
return a[x].rev(lca(a[x].idx(u),a[y].idx(v)));
}
ll Dep(ll k) {
return a[Idx(k)].Dep(k);
}
ll Dis(ll u,ll v) {
return (Dep(u)+Dep(v))-(Dep(Lca(u,v))<<1);
}
int main() {
#ifdef Plus_Cat
freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
I(n,m,Q),g.Init(),cnt=n;
FOR(i,2,n) {
int u,v;
I(u,v),g.con(u,v);
}
dfs0(1),top[1]=1,dfs1(1);
FOR(i,1,n)seg.Plus(dfn[i],seg[i],seg[i-1]);
a[tot=1]= {1,1,1,1,1,1,{}};
FOR(i,1,m) {
int ty;
ll pa;
I(ty,pa),Build(ty,pa,a[++tot]);
}
FOR(i,1,Q) {
ll u,v;
I(u,v),O(Dis(u,v),'\n');
}
return 0;
}

浙公网安备 33010602011771号