题解 P4183 【[USACO18JAN]Cow at Large P】

y2823774827y

2019-03-01 11:56:16

Solution

~~感觉楼下写的有点不清楚,反正我看不懂,这么说dalao是不是有点不好~~ 显然,$g_i$为$i$到最近叶子节点的距离,$d_i$为$i$的度数 假设我们要求的是$ans_u$,如果把$u$作为根,$dep_i≥g_i$则$i$这棵子树贡献为$1$就能拦截$u$,但为了保证唯一性,$dep_i≥g_i \&\& dep_{fa_{i}}<g_{fa_{i}}$ 时间复杂度$O(n^2)$ 点对贡献,考虑用点分治优化 对于一棵**子树**,$\sum\limits^m d_i=2m-1,\therefore 1=\sum\limits^m (2-d_i)$,根据子树贡献单调性,$ans_u=\sum\limits_{i=1}^n [dis(u,i)≥g_i](2-d_i)$ 至此,该题转换成点分治模板题,时间复杂度$O(nlog^2n)$ 乱七八糟的代码: ```cpp #include<bits/stdc++.h> using namespace std; typedef int LL; const LL maxn=1e5,inf=0x3f3f3f3f; struct node{ LL to,nxt; }dis[maxn<<1]; LL n,root,num,up,N,mi,tim; LL ans[maxn],head[maxn],d[maxn],g[maxn],tree[maxn],visit[maxn],size[maxn],V[maxn]; inline void Add(LL u,LL v){ dis[++num]=(node){v,head[u]}, head[u]=num; ++d[v]; } void Dfs1(LL u,LL f){ if(d[u]==1) g[u]=0; for(LL i=head[u];i;i=dis[i].nxt){ LL v(dis[i].to); if(v==f) continue; Dfs1(v,u); g[u]=min(g[u],g[v]+1); } } void Dfs2(LL u,LL f){ for(LL i=head[u];i;i=dis[i].nxt){ LL v(dis[i].to); if(v==f) continue; g[v]=min(g[v],g[u]+1); Dfs2(v,u); } } inline LL Lowbit(LL x){ return x&-x; } inline LL Query(LL x){ LL ret(0); x+=up; for(;x;x-=Lowbit(x)) ret+=tree[x]; return ret; } inline void Modify(LL x,LL val){ x+=up; for(;x<=100000;x+=Lowbit(x)) tree[x]+=val; } void Dfs(LL u){ LL mx(0); visit[u]=true; size[u]=1; for(LL i=head[u];i;i=dis[i].nxt){ LL v(dis[i].to); if(visit[v]) continue; Dfs(v); size[u]+=size[v]; mx=max(mx,size[v]); }mx=max(mx,N-size[u]); if(mi>mx) mi=mx,root=u; visit[u]=false; } void Get(LL u,LL dt){ ans[u]+=Query(dt); visit[u]=true; for(LL i=head[u];i;i=dis[i].nxt){ LL v(dis[i].to); if(visit[v]) continue; Get(v,dt+1); }visit[u]=false; } void Up(LL u,LL dt){ Modify(g[u]-dt,2-d[u]); visit[u]=true; for(LL i=head[u];i;i=dis[i].nxt){ LL v(dis[i].to); if(visit[v]) continue; Up(v,dt+1); }visit[u]=false; } void Clear(LL u,LL dt){ Modify(g[u]-dt,-(2-d[u])); visit[u]=true; for(LL i=head[u];i;i=dis[i].nxt){ LL v(dis[i].to); if(visit[v]) continue; Clear(v,dt+1); }visit[u]=false; } void Div(LL u){ mi=inf, Dfs(u); u=root; visit[u]=true; LL top(0); for(LL i=head[u];i;i=dis[i].nxt){ LL v(dis[i].to); if(visit[v]) continue; V[++top]=v; Get(v,1); Up(v,1); } for(LL i=head[u];i;i=dis[i].nxt){ LL v(dis[i].to); if(visit[v]) continue; Clear(v,1); } Modify(g[u],2-d[u]); for(LL i=top;i>=1;--i){ LL v(V[i]); Get(v,1); Up(v,1); }ans[u]+=Query(0); Modify(g[u],-(2-d[u])); for(LL i=head[u];i;i=dis[i].nxt){ LL v(dis[i].to); if(visit[v]) continue; Clear(v,1); } for(LL i=head[u],sum=N;i;i=dis[i].nxt){ LL v(dis[i].to); if(visit[v]) continue; N=(size[v]>size[u]?sum-size[u]:size[v]); Div(v); } } int main(){ cin>>n; up=n; for(LL i=1;i<n;++i){ LL u,v; cin>>u>>v; Add(u,v), Add(v,u); } memset(g,inf,sizeof(g)); Dfs1(1,0), Dfs2(1,0); N=n; Div(1); for(LL i=1;i<=n;++i) if(d[i]==1) cout<<1<<endl;else cout<<ans[i]<<endl; return 0; } ```