BZOJ3648 : 寝室管理
2014-07-23 16:50
239 查看
求环套外向树上节点数不小于K的路径数。
首先树的话直接点分治+树状数组$O(n\log^2n)$搞定
环套树的话,先删掉多余的边(a,b)
然后变成了一棵树,直接点分治
然后在树上找到a到b的路径,将每一棵子树中的点的“所有权”(要么从a出发到达,要么从b出发到达)改变一下,然后计算贡献即可。
总时间复杂度$O(n\log^2n+n\log n)$
把BZOJ第700题献给了这道题…
首先树的话直接点分治+树状数组$O(n\log^2n)$搞定
环套树的话,先删掉多余的边(a,b)
然后变成了一棵树,直接点分治
然后在树上找到a到b的路径,将每一棵子树中的点的“所有权”(要么从a出发到达,要么从b出发到达)改变一下,然后计算贡献即可。
总时间复杂度$O(n\log^2n+n\log n)$
把BZOJ第700题献给了这道题…
#include<cstdio> #define N 100010 typedef long long ll; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} int n,m,K,i,x,y,g ,nxt[N<<1],v[N<<1],ok[N<<1],ed=1,son ,f ,size,now,fa ,exa,exb,to ,way ,cnt,in ,dis ,t ,pos; ll ans,bit ; inline void addedge(int x,int y){v[++ed]=y,nxt[ed]=g[x],ok[ed]=1,g[x]=ed;} int F(int x){return fa[x]==x?x:fa[x]=F(fa[x]);} inline void add(int x){for(;x<=n;x+=x&-x)if(t[x]!=pos)t[x]=pos,bit[x]=1;else bit[x]++;} inline void del(int x){for(;x<=n;x+=x&-x)bit[x]--;} inline ll sum(int x){if(x<0)return 0;ll y=0;for(;x;x-=x&-x)if(t[x]==pos)y+=bit[x];return y;} void findroot(int x,int pre){ son[x]=1;f[x]=0; for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=pre){ findroot(v[i],x); son[x]+=son[v[i]]; if(son[v[i]]>f[x])f[x]=son[v[i]]; } if(size-son[x]>f[x])f[x]=size-son[x]; if(f[x]<f[now])now=x; } void dfscal(int x,int pre,int dep){ ans+=sum(n)-sum(K-dep-1); for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=pre)dfscal(v[i],x,dep+1); } void dfsadd(int x,int pre,int dep){ add(dep+1); for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=pre)dfsadd(v[i],x,dep+1); } void solve(int x){ int i; pos++,add(1); for(i=g[x];i;i=nxt[i])if(ok[i])dfscal(v[i],x,1),dfsadd(v[i],x,1); for(i=g[x];i;i=nxt[i])if(ok[i])ok[i^1]=0,f[0]=size=son[v[i]],findroot(v[i],now=0),solve(now); } void path(int x,int pre,int d){ to[x]=pre,add(dis[x]=d); for(int i=g[x];i;i=nxt[i])if(v[i]!=pre)path(v[i],x,d+1); } void treecal(int x,int pre,int d){ ans+=sum(n)-sum(K-d-1); for(int i=g[x];i;i=nxt[i])if(v[i]!=pre&&!in[v[i]])treecal(v[i],x,d+1); } void treedel(int x,int pre){ del(dis[x]); for(int i=g[x];i;i=nxt[i])if(v[i]!=pre&&!in[v[i]])treedel(v[i],x); } int main(){ read(n),read(m),read(K); for(i=1;i<=n;i++)fa[i]=i; while(m--){ read(x),read(y); if(F(x)==F(y))exa=x,exb=y;else fa[fa[x]]=fa[y],addedge(x,y),addedge(y,x); } f[0]=size=n,findroot(1,now=0),solve(now); if(exa){ pos++,path(exa,0,1); for(i=exb;i;i=to[i])in[way[++cnt]=i]=1; for(i=1;i<cnt;i++)treedel(way[i],0),treecal(way[i],0,i); } return printf("%lld",ans),0; }
相关文章推荐
- BZOJ3648 寝室管理 【点分治 + 环套树】
- bzoj3648 寝室管理
- [BZOJ3648]寝室管理(点分治+bit)
- 【BZOJ3648】寝室管理 树分治
- BZOJ3648: 寝室管理
- 【bzoj3648】【寝室管理】【环套树+点分治+树状数组】
- 用C#做的一个小项目,寝室管理系统
- BZOJ 3648|寝室管理|点分治|树状数组|平衡树
- 寝室管理
- 【BZOJ-3648】寝室管理 环套树 + 树状数组 + 点分治
- bzoj3648 寝室管理 树分治
- BZOJ 3648: 寝室管理 树的点分治+乱搞
- BZOJ 3648: 寝室管理( 点分治 + 树状数组 )
- 学生寝室管理系统
- [JZOJ3978] 寝室管理
- [树的点分治] [BZOJ3648] 寝室管理
- Linux系统管理技巧大荟萃
- 信息技术管理部门的日常工作条例
- NetSniper网络尖兵:宽带网络运营维护管理器