zoukankan      html  css  js  c++  java
  • 【日常训练】【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;
    }
    
  • 相关阅读:
    DPDK — 网卡初始化流程(Intel 82599 ixgbe 网卡驱动示例)
    leetcode 3. 无重复字符的最长子串
    20193120 实验四 Python综合实践
    hadoop常用的端口号
    Django学习笔记
    ORACLE EBS AP invoice 到付款的数据流
    EBS 系统标准职责定义MAP
    Advanced Pricing
    Oracle Advanced Pricing White Papers
    增加AP INVOICE 行&分配行
  • 原文地址:https://www.cnblogs.com/czyarl/p/14482461.html
Copyright © 2011-2022 走看看