dtoi4545「HNOI2016」树
题意:
https://loj.ac/p/2050
题解:
此题思路非常清晰,最后的大树可以看做是由 $m+1$ 个节点,每个节点内部又是一棵树组成的。
考虑外层的树怎么建,对于一个插入操作,可以先二分它的父亲是哪一个节点,顺便还可以求一下模板树的某个子树的第 $k$ 大来确定到底是连在谁身上,用dfs序+主席树就可以维护了,还要维护一下每个节点最上面的点的真实深度(用longlong存)。
内层的树不需要建,只需要知道根节点是哪个就可以了。
然后处理查询操作,查询操作要做的就是求出两个点及其lca的深度就行,两个点的深度很好求,用所在的节点的根的深度+模板树中该点和这个节点的根的深度之差就行。求lca的话,先求外层的lca,再求里层的lca,最后算深度。这里稍微分下类,考虑下外层节点的关系就可以了。代码其实非常好写,也没啥细节。
#include<cstdio> #include<vector> #include<algorithm> #include<cstdlib> using namespace std; int n,m,q,dfn[100003],df[100002],tim,fa[22][100003],dep[100003],zjds[100003],cnt,rt[100002]; int fa2[22][100003],dep2[100003]; long long sum[100003]; vector<int>g[100003]; typedef struct{ int ls,rs,sum; }XDS; typedef struct{ int rt,x;long long dep; }P; XDS xds[4000002]; P p[100003]; void dfs(int x,int y){ zjds[x]=1;dep[x]=dep[y]+1;fa[0][x]=y;dfn[x]=++tim;df[tim]=x; for (int i=0;i<g[x].size();i++) if (g[x][i]!=y) { dfs(g[x][i],x);zjds[x]+=zjds[g[x][i]]; } } int lca(int x,int y){ if (dep[x]<dep[y])swap(x,y); int k=dep[x]-dep[y]; for (int i=0;i<=20;i++) if ((1<<i)&k)x=fa[i][x]; if (x==y)return x; for (int i=20;i>=0;i--) if (fa[i][x]!=fa[i][y]) { x=fa[i][x];y=fa[i][y]; } return fa[0][x]; } void gengxin(int r1,int r2,int begin,int end,int wz){ if (begin==end) { xds[r2].sum=xds[r1].sum+1; return; } int mid=(begin+end)/2; if (wz<=mid) { xds[r2].rs=xds[r1].rs;xds[r2].ls=++cnt; gengxin(xds[r1].ls,xds[r2].ls,begin,mid,wz); } else { xds[r2].ls=xds[r1].ls;xds[r2].rs=++cnt; gengxin(xds[r1].rs,xds[r2].rs,mid+1,end,wz); } xds[r2].sum=(xds[xds[r2].ls].sum+xds[xds[r2].rs].sum); } int chaxun(int r1,int r2,int begin,int end,int k){ if (begin==end)return begin; int mid=(begin+end)/2; if (xds[xds[r2].ls].sum-xds[xds[r1].ls].sum>=k)return chaxun(xds[r1].ls,xds[r2].ls,begin,mid,k); else return chaxun(xds[r1].rs,xds[r2].rs,mid+1,end,k-(xds[xds[r2].ls].sum-xds[xds[r1].ls].sum)); } int fin(long long x){ int lef=1,righ=m+1,mid; while(lef<righ) { mid=(lef+righ)/2; if (sum[mid]>=x)righ=mid;else lef=mid+1; } return lef; } int findd(long long x){ int lef=fin(x); return chaxun(rt[dfn[p[lef].rt]-1],rt[dfn[p[lef].rt]+zjds[p[lef].rt]-1],1,n,x-sum[lef-1]); } long long jsdep(long long x){ int lef=fin(x),wz=findd(x); return p[lef].dep+dep[wz]-dep[p[lef].rt]; } bool isfa2(int x,int y){ int k=dep2[x]-dep2[y]; for (int i=0;i<=20;i++) if ((1<<i)&k)x=fa2[i][x]; return (x==y); } long long jslca(long long x,long long y){ int fx=fin(x),fy=fin(y); if (dep2[fx]<dep2[fy]){swap(x,y);swap(fx,fy);} if (fx==fy) { int lc=lca(findd(x),findd(y)); return p[fx].dep+dep[lc]-dep[p[fx].rt]; } else if (isfa2(fx,fy)) { int k=dep2[fx]-dep2[fy]-1; for (int i=0;i<=20;i++) if ((1<<i)&k)fx=fa2[i][fx]; int lc=lca(p[fx].x,findd(y)); return p[fy].dep+dep[lc]-dep[p[fy].rt]; } else { int k=dep2[fx]-dep2[fy]; for (int i=0;i<=20;i++) if ((1<<i)&k)fx=fa2[i][fx]; for (int i=20;i>=0;i--) if (fa2[i][fx]!=fa2[i][fy]) { fx=fa2[i][fx];fy=fa2[i][fy]; } int lc=lca(p[fx].x,p[fy].x); fx=fa2[0][fx]; return p[fx].dep+dep[lc]-dep[p[fx].rt]; } } int main() { scanf("%d%d%d",&n,&m,&q); for (int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v);g[u].push_back(v);g[v].push_back(u); } dfs(1,0); for (int i=1;i<=n;i++) { rt[i]=++cnt;gengxin(rt[i-1],rt[i],1,n,df[i]); } for (int i=1;i<=20;i++) for (int j=1;j<=n;j++) fa[i][j]=fa[i-1][fa[i-1][j]]; p[1].rt=1;p[1].dep=0;sum[1]=n;dep2[1]=0; for (int i=2;i<=m+1;i++) { int a;long long b; scanf("%d%lld",&a,&b); int lef=1,righ=i-1,mid,nw; while(lef<righ) { mid=(lef+righ)/2; if (sum[mid]>=b)righ=mid;else lef=mid+1; } nw=lef;fa2[0][i]=nw;dep2[i]=dep2[nw]+1; p[i].rt=a;p[i].x=chaxun(rt[dfn[p[nw].rt]-1],rt[dfn[p[nw].rt]+zjds[p[nw].rt]-1],1,n,b-sum[nw-1]); p[i].dep=p[nw].dep+(dep[p[i].x]-dep[p[nw].rt])+1; sum[i]=sum[i-1]+zjds[a]; } for (int i=1;i<=20;i++) for (int j=1;j<=m+1;j++) fa2[i][j]=fa2[i-1][fa2[i-1][j]]; for (int i=1;i<=q;i++) { long long a,b; scanf("%lld%lld",&a,&b); printf("%lld\n",jsdep(a)+jsdep(b)-2*jslca(a,b)); } return 0; }