长链剖分练习
按照这篇博客 学了一下长链剖分.
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);
}

浙公网安备 33010602011771号