【日常训练】【BZOJ】20210304_T2_树tree_树链剖分/dp/dp优化_Bzoj3644

题面

HZY 种了一棵树,如果你不知道树是啥,你可以直接去秒 T3 或者看百度给的详细解释: 树是具有木质树干及树枝的植物,可存活多年。一般将乔木称为树,主干,植株一,分枝距离地面较高,可以形成树冠,树有很多种。

为了方便 HZY 在树上走,她在树上的每个节点 i 都建了一个回旋加速喷气式阿姆斯特朗炮,可以把她发射到和点 i 距离不超过 a[i]的任意一个点上(两点间距离定义为它们之间边的数量),现在 HZY 想知道从一个点 x 到另一个点 y 至少要用几次回旋加速喷气式阿姆斯特朗炮(她不能通过回旋加速喷气式阿姆斯特朗
炮以外的方式移动)。(以及,必须在x和y之间的简单路径上移动)。

另外,有时候有些节点上的回旋加速喷气式阿姆斯特朗炮会进/退化。形式化的,有 m 个操作,每个形如 o,x,y 的形式,若 o 为 C,则表示把 a[x]改成 y;若 o 为 Q,则表示查询 x,y,查询保证 x!=y。

对于前 100%的数据,1≤n,m≤100000,1≤a[i]≤20。

黑暗爆炸OJ 3644

题解

现场得分:60/10

现场题面里少了一句话导致这道题不太能做。

  • 有一个简单的(O(nm))的链上dp的做法。记(f_i)表示从开头到(i)最少要多少步。
  • 我们考虑用树剖来维护链上的dp。
  • 考虑为了合并信息,我们应该如何记录一个点上的东西。
  • 我们发现对于一个表示的区间为([l,r])的节点,我们可以记录三种东西:
    • (f_{i}),表示从(l+i-1)开始,至少到(r)结束(可以超出去),我们最少要多少步。
    • (g_{i}),表示从(l+i-1)开始,至少到(r)结束(可以超出去),在(f_i)最小的情况下最多超出去多少。
    • 我们发现可能会有这一段亏一步来拿到一个20的长步子,但是又最多只会亏一步。所以我们再记录([l,r])中的(max i+a_i),其中(a_i)表示在(i)上可以跨多少步。
  • 直接转移。
  • 修改点值的时候, 一次是(20log n)的。
  • 注意回答询问的时候,我们只需要维护(f_1,g_1),所以回答的时候是(log^2 n)的。
  • 复杂度(O(nalog n+nlog^2n))

代码

#include<bits/stdc++.h>
#define LL long long
#define MAXN 101000
using namespace std;
template<typename T> void Read(T &cn)
{
	char c; int sig = 1;
	while(!isdigit(c = getchar())) if(c == '-') sig = 0;
	if(sig) {cn = c-48; while(isdigit(c = getchar())) cn = cn*10+c-48; }
	else    {cn = 48-c; while(isdigit(c = getchar())) cn = cn*10+48-c; }
}
template<typename T> void Write(T cn)
{
	int wei = 0; T cm = 0; int cx = cn%10; cn/=10;
	if(cn < 0 || cx < 0) {putchar('-'); cn = 0-cn; cx = 0-cx; }
	while(cn)cm = cm*10+cn%10,cn/=10,wei++;
	while(wei--)putchar(cm%10+48),cm/=10;
	putchar(cx+48);
}
template<typename T> void WriteL(T cn) {Write(cn); puts(""); }
template<typename T> void WriteS(T cn) {Write(cn); putchar(' '); }
template<typename T> void Max(T &cn, T cm) {cn = cn < cm ? cm : cn; }
template<typename T> void Min(T &cn, T cm) {cn = cn < cm ? cn : cm; }
struct Dp{
	int yuan, len;
	int f[21], g[21];
	void outit() 
	{
		printf("yuan = %d len = %d ",yuan,len);
		for(int i = 1;i<=2;i++) printf("f[%d] = %d g[%d] = %d ",i,f[i],i,g[i]);
		puts("");
	}
	void pre(int cn) {len = cn; for(int i = 0;i<=20;i++) f[i] = MAXN+1, g[i] = 0, f[1] = 0; g[1] = 1; yuan = 0; }
	void set(int cn) 
	{
		yuan = cn; 
		for(int i = 1;i<=20;i++) f[i] = 0, g[i] = i-1;
		f[0] = MAXN; g[0] = 0;
	}
};
void update(Dp &cn, Dp ls, Dp rs, int cm)
{
//	printf("in update : cm = %d
",cm);
//	printf("  ls = "); ls.outit();
//	printf("  rs = "); rs.outit();
	cn.yuan = max(rs.yuan, ls.yuan-rs.len); cn.len = ls.len + rs.len;
	cn.f[0] = MAXN+1, cn.g[0] = 0;
	for(int i = 1;i<=cm;i++)
	{
		if(i >= cn.len) cn.f[i] = 0, cn.g[i] = i-cn.len;
		cn.f[i] = ls.f[i] + rs.f[ls.g[i]], cn.g[i] = rs.g[ls.g[i]];
		int lin = ls.f[i]+1 + rs.f[ls.yuan], lin2 = rs.g[ls.yuan];
		if(lin < cn.f[i] || (lin == cn.f[i] && lin2 > cn.g[i])) cn.f[i] = lin, cn.g[i] = lin2;
	}
//	printf("  cn = "); cn.outit();
}
struct Seg{
	Dp t[MAXN*4+1];
	int n;
	void build(int cn, int l, int r, int a[])
	{
		t[cn].pre(r-l+1); if(l == r) {t[cn].set(a[l]); return; }
		int zh = (l+r)>>1; build(cn<<1,l,zh,a); build((cn<<1)|1,zh+1,r,a);
		update(t[cn], t[cn<<1], t[(cn<<1)|1], 20);
	}
	void gai(int cn, int cm, int cx, int l, int r)
	{
		if(l == r) {t[cn].set(cx); return; }
		int zh = (l+r)>>1; 
		if(cm <= zh) gai(cn<<1,cm,cx,l,zh);
		else gai((cn<<1)|1,cm,cx,zh+1,r);
		update(t[cn], t[cn<<1], t[(cn<<1)|1], 20);
	}
	void qiu(int cn, int cl, int cr, int l, int r, Dp &ans)
	{
		if(cl <= l && r <= cr) {
//			printf("re qiu : cn = %d l = %d r = %d
",cn,l,r); 
			update(ans, ans, t[cn], 1); return; 
		}
		int zh = (l+r)>>1;
		if(cl <= zh) qiu(cn<<1, cl, cr, l, zh, ans);
		if(cr >  zh) qiu((cn<<1)|1, cl,cr,zh+1,r,ans);
	}
	void build(int cn, int a[]) {n = cn; build(1,1,n,a); }
	void gai(int cn, int cm) {gai(1,cn,cm,1,n); }
	void qiu(int cl, int cr, Dp &ans) {qiu(1,cl,cr,1,n,ans); }
}T1, T2;
struct qwe{
	int a,b,ne;
	void mk(int cn, int cm, int cx) {a = cn; b = cm; ne = cx; }
};
struct Qujian{
	int l, r;
	void mk(int cn, int cm) {l = cn; r = cm; }
};
qwe a[MAXN*2+1];
int alen;
int head[MAXN+1];
int n, q;
int zhi[MAXN+1], zhi2[MAXN+1];
int dfn[MAXN+1], lie[MAXN+1], shi;
int fa[MAXN+1], size[MAXN+1], shen[MAXN+1];
int top[MAXN+1], zhong[MAXN+1];
Qujian zhan1[MAXN+1], zhan2[MAXN+1];
int zlen1, zlen2;
void lian(int cn, int cm) {a[++alen].mk(cn,cm,head[cn]); head[cn] = alen; }
void dfs1(int cn)
{
	size[cn] = 1; zhong[cn] = 0;
	for(int i = head[cn];i;i = a[i].ne)
	{
		int y = a[i].b;
		if(y == fa[cn]) continue;
		fa[y] = cn; shen[y] = shen[cn]+1; 
		dfs1(y); size[cn] += size[y];
		if(size[zhong[cn]] < size[y]) zhong[cn] = y;
	}
}
void dfs2(int cn)
{
	lie[dfn[cn] = ++shi] = cn;
	if(zhong[cn]) {
		top[zhong[cn]] = top[cn];
		dfs2(zhong[cn]);
	}
	for(int i = head[cn];i;i = a[i].ne)
	{
		int y = a[i].b;
		if(y == fa[cn] || y == zhong[cn]) continue;
		top[y] = y; dfs2(y);
	}
}
int suan(int cn, int cm)
{
	zlen1 = zlen2 = 0;
	while(top[cn] != top[cm])
	{
		if(shen[top[cn]] < shen[top[cm]]) zhan2[++zlen2].mk(dfn[top[cm]], dfn[cm]), cm = fa[top[cm]];
		else zhan1[++zlen1].mk(dfn[top[cn]], dfn[cn]), cn = fa[top[cn]];
	}
	if(shen[cn] < shen[cm]) zhan2[++zlen2].mk(dfn[cn], dfn[cm]);
	else zhan1[++zlen1].mk(dfn[cm], dfn[cn]);
	Dp ans; ans.pre(0);
	for(int i = 1;i<=zlen1;i++) T2.qiu(n-zhan1[i].r+1, n-zhan1[i].l+1, ans);
	for(int i = zlen2;i>=1;i--) T1.qiu(zhan2[i].l, zhan2[i].r, ans);
	int guo = ans.f[1];
	for(int i = 2;i<=20;i++) Min(guo, ans.f[i]);
	return guo;
}
int main()
{
//	freopen("tree.in","r",stdin);
//	freopen("tree.out","w",stdout);
	Read(n);
	for(int i = 1;i<=n;i++) Read(zhi[i]);
	alen = 0; memset(head,0,sizeof(head));
	for(int i = 2;i<=n;i++) {int bx,by; Read(bx); Read(by); lian(bx,by); lian(by,bx); }
	shi = 0; shen[1] = 1; shen[0] = 0; fa[1] = fa[0] = 0; top[1] = 1; size[0] = 0;
	dfs1(1); dfs2(1);
	for(int i = 1;i<=n;i++) zhi2[i] = zhi[lie[i]];
	T1.build(n, zhi2); 
	for(int i = 1;i<=n/2;i++) swap(zhi2[i], zhi2[n-i+1]);
	T2.build(n, zhi2);
	Read(q);
	for(int i = 1;i<=q;i++)
	{
		char bc; int bx, by; 
		while(!isalpha(bc = getchar())); Read(bx); Read(by);
		if(bc == 'C') {zhi[bx] = by; T1.gai(dfn[bx], by); T2.gai(n-dfn[bx]+1, by); }
		if(bc == 'Q') WriteL(suan(bx,by));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/czyarl/p/14482461.html