[POI2014][BZOJ3522/4543]Hotel/[JZOJ5357]校门外的树
2017-09-11 22:41
405 查看
题目大意
给定一棵n个点的树,求树上两两距离相等的点三元组个数。1≤n≤105
题目分析
考虑dp。令fx,i表示x为根的子树内,距离x为i的点的个数;gx,i表示以x为根的子树中,到x距离相等而且到lca的距离比lca到x距离要大i的点对个数(说白了就是那些可能的在x子树外的第三个点伸出了x子树i的距离)。
然后在dp各个子树之前,我们有fx,0=1,ans+=gx,0。
对于一个子树y,我们有
ansgx,i+1gx,i−1fx,i+1+=fx,igy,i+1+gx,i+1fy,i+=fx,i+1fy,i+=gy,i+=fy,i
这样我们就可以做到O(n2)的时间和空间复杂度。
怎么将时空复杂度优化呢?注意到对于节点x,设y是我们第一个枚举的子树,那么gx,i−1=gy,i,fx,i+1=fy,i,是数组位移一位的关系。
我们不妨对这棵树长链剖分,然后将重儿子作为第一次枚举的子树,使用类似指针的思路来做到O(1)的数组位移,然后其余的子树直接暴力转移。
这样做时间复杂度是O(n)的,因为一个点x所在的子树被暴力转移当且仅当x是一条长链的顶端,而且转移复杂度是O(depx)的,也就是和长链长成正比的。因此总的转移复杂度就是所有长链长的和,也就是O(n)的。
至于空间复杂度,我们给每条长链顶端分配正比于长链长度的空间就好了,最后也是O(n)的。
一些实现细节请读者自行思考。
代码实现
#include <iostream> #include <cstdio> #include <cctype> using namespace std; typedef long long LL; int read() { int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar(); while (isdigit(ch)) x=x*10+ch-'0',ch=getchar(); return x*f; } const int N=100005; const int M=N<<1; const int E=N<<1; int last ,hea ,depth ,lng ,mxl ,fa ,fst ,gst ; int tov[E],nxt[E]; LL f ,g[M]; int n,tot,fcnt,gcnt; LL ans; void insert(int x,int y){tov[++tot]=y,nxt[tot]=last[x],last[x]=tot;} void dfs(int x) { mxl[x]=lng[x]=0; for (int i=last[x],y;i;i=nxt[i]) if ((y=tov[i])!=fa[x]) { depth[y]=depth[fa[y]=x]+1,dfs(y); if (mxl[x]<mxl[y]+1) mxl[x]=mxl[lng[x]=y]+1; } } void dp(int x,int top) { if (x==top) fst[x]=fcnt,fcnt+=mxl[x]+1,gst[x]=gcnt,gcnt+=mxl[x]<<1|1; if (lng[x]) dp(lng[x],top); int fptr=fst[top]+depth[x]-depth[top],gptr=gst[top]+mxl[top]-depth[x]+depth[top]; ++f[fptr],ans+=g[gptr]; for (int i=last[x],y;i;i=nxt[i]) if ((y=tov[i])!=fa[x]&&y!=lng[x]) { dp(y,y); for (int j=0;j<mxl[y];++j) ans+=f[fptr+j]*g[gst[y]+mxl[y]+j+1]; for (int j=0;j<=mxl[y]&&gptr+j+1<gst[top]+(mxl[top]<<1|1);++j) ans+=g[gptr+j+1]*f[fst[y]+j]; for (int j=0;j<=mxl[y]&&gptr+j+1<gst[top]+(mxl[top]<<1|1)&&fptr+j+1<fst[top]+mxl[top]+1;++j) g[gptr+j+1]+=f[fptr+j+1]*f[fst[y]+j]; for (int j=0;j<mxl[y];++j) g[gptr+j]+=g[gst[y]+mxl[y]+j+1]; for (int j=0;j<=mxl[y]&&fptr+j+1<fst[top]+mxl[top]+1;++j) f[fptr+j+1]+=f[fst[y]+j]; } } int main() { freopen("tree.in","r",stdin),freopen("tree.out","w",stdout); n=read(); for (int i=1,x,y;i<n;++i) x=read(),y=read(),insert(x,y),insert(y,x); depth[1]=1,dfs(1),fcnt=gcnt=1,dp(1,1),printf("%lld\n",ans); fclose(stdin),fclose(stdout); return 0; }
相关文章推荐
- BZOJ 3522 & 4543: [POI2014]Hotel
- BZOJ4543/BZOJ3522 [POI2014]Hotel加强版
- [树形DP 启发式合并 神题] BZOJ 4543 [POI2014]Hotel加强版 & BZOJ 3522 [Poi2014]Hotel
- 【XSY1536】【BZOJ3522】【BZOJ4543】【POI2014】Hotel 树形DP 长链剖分 启发式合并
- [bzoj3522][bzoj4543][POI2014]HOTEL
- bzoj4543[POI2014]Hotel
- [bzoj4543] [POI2014]Hotel加强版
- 【DFS】BZOJ3522-[Poi2014]Hotel
- BZOJ 4543 POI2014 hotel
- 【bzoj3522】[Poi2014]Hotel 树形dp
- BZOJ4543: [POI2014]Hotel加强版 长链剖分
- 【bzoj3522】【poi2014】【hotel】【树形dp】
- bzoj3522 [Poi2014]Hotel dfs(DP)
- 【bzoj3522】[Poi2014]Hotel
- [bzoj3522][Poi2014]Hotel(暴力)
- BZOJ3522: [Poi2014]Hotel
- 【BZOJ3522】[Poi2014]Hotel 树形DP
- BZOJ.3522.[POI2014]Hotel(DP)
- BZOJ 4543: [POI2014]Hotel加强版 长链剖分
- [Poi2014][BZOJ3522] Hotel