长链剖分练习
按照这篇博客 学了一下长链剖分.
1. CF 1009F Dominant Indices
大意: 给定树, 定义$d_{x,i}$为$x$子树内到$x$距离为$i$的点的个数. 对于每个点$x$, 输出使$d_{x,i}$最大的$i$, 有多个输出最小的.
#include <iostream> #include <cstdio> #include <queue> #define REP(i,a,n) for(int i=a;i<=n;++i) #define pb push_back using namespace std; const int N = 1e6+10; int n, dep[N], son[N], ans[N]; int *f[N], tmp[N], *id=tmp; vector<int> g[N]; void dfs(int x, int fa) { for (int y:g[x]) if (y!=fa) { dfs(y,x); if (dep[y]>dep[son[x]]) son[x]=y; } dep[x] = dep[son[x]]+1; } void dfs2(int x, int fa) { f[x][0] = 1; if (son[x]) { f[son[x]]=f[x]+1; dfs2(son[x],x); ans[x]=ans[son[x]]+1; if (f[x][ans[x]]==1) ans[x]=0; } for (int y:g[x]) if (!f[y]) { f[y]=id,id+=dep[y]; dfs2(y,x); REP(j,1,dep[y]) { f[x][j]+=f[y][j-1]; if (j<ans[x]&&f[x][j]>=f[x][ans[x]]||j>ans[x]&&f[x][j]>f[x][ans[x]]) { ans[x] = j; } } } } int main() { scanf("%d", &n); REP(i,2,n) { int u, v; scanf("%d%d", &u, &v); g[u].pb(v),g[v].pb(u); } dfs(1,0); f[1]=id,id+=dep[1],dfs2(1,0); REP(i,1,n) printf("%d\n",ans[i]); }
2. COGS 2652
大意: 给定树, 点$i$有权值$a_i,b_i$, 求长$m$的路径使得$\frac{\sum a_i}{\sum b_i}$最小
二分答案, 转为求(\sum a_i-x\sum b_i)的最小值. 长度固定的树链最小值可以用长链剖分$O(n)$求出.
为了$O(1)$从儿子转移到父亲, 需要对每个$f$值减去重儿子所在长链和.
#include <iostream> #include <algorithm> #include <cstdio> #include <math.h> #include <set> #include <map> #include <queue> #include <string> #include <string.h> #include <bitset> #define REP(i,a,n) for(int i=a;i<=n;++i) #define PER(i,a,n) for(int i=n;i>=a;--i) #define hr putchar(10) #define pb push_back using namespace std; const double INF = 1e18; const int N = 1e6+10; int n,m,a[N],b[N],dep[N],son[N]; double *f[N],tmp[N],*id,c[N],val[N],ret; vector<int> g[N]; void dfs1(int x, int fa) { for (int y:g[x]) if (y!=fa) { dfs1(y,x); if (dep[y]>dep[son[x]]) son[x]=y; } dep[x]=dep[son[x]]+1; } void upd(int x) { f[x]=id,id+=dep[x]; } void dfs(int x, int fa) { f[x][0] = 0; if (son[x]) { f[son[x]]=f[x]+1; dfs(son[x],x); val[x]+=val[son[x]]; f[x][0]-=val[son[x]]; } for (int y:g[x]) if (y!=fa&&y!=son[x]) { upd(y),dfs(y,x); PER(j,0,min(dep[y],m)-1) { if (m-j-1<dep[x]) { ret = min(ret, f[y][j]+val[y]+f[x][m-j-1]+val[x]); } } PER(j,0,min(dep[y],m)-1) { f[x][j+1]=min(f[x][j+1],f[y][j]+val[y]-val[x]+c[x]); } } if (m<dep[x]) ret=min(ret,f[x][m]+val[x]); } int chk(double x) { memset(tmp,0x7f,sizeof tmp); id=tmp,ret=tmp[0]; REP(i,1,n) val[i]=c[i]=a[i]-x*b[i]; upd(1),dfs(1,0); return ret<0; } int main() { freopen("cdcq_b.in","r",stdin); freopen("cdcq_b.out","w",stdout); scanf("%d%d", &n, &m),--m; REP(i,1,n) scanf("%d",a+i); REP(i,1,n) scanf("%d",b+i); REP(i,2,n) { int u, v; scanf("%d%d", &u, &v); g[v].pb(u),g[u].pb(v); } if (m==-2||!m) { double ans = INF; REP(i,1,n) ans = min(ans,(double)a[i]/b[i]); printf("%.2lf\n",ans); return 0; } dfs1(1,0); double l = 0, r = INF,ans=-1; REP(i,1,400) { double mid = (l+r)/2; if (chk(mid)) ans=mid,r=mid; else l=mid; } if (ans==-1) puts("-1"); else printf("%.2lf\n", ans); }