长链剖分练习

按照这篇博客 学了一下长链剖分.

 

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);
}
 

 

posted @ 2019-07-15 21:04  uid001  阅读(136)  评论(0编辑  收藏  举报