ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P4332 [SHOI2014]三叉神经树

2022-04-04 15:33:29  阅读:136  来源: 互联网

标签:log 修改 int up push 三叉神经 SHOI2014 mathcal P4332


要求维护一棵树:

  • 每个点有 \(3\) 个端口,分为输入端和输出端(连向父亲)。输出端的个数 \(\leq 1\)。
  • 如果一个点输入端权值为 \(1\) 的个数 \(\geq 2\),那么这个点的权值为 \(1\),否则为 \(0\)。
  • 支持动态修改叶子节点,修改后询问根节点的权值。

\(1 \leq n \leq 5\times 10^5\),时限 \(4\text{s}\),空限 \(250\text{MB}\)。

sol

可以发现,每一次修改叶子节点后,权值改变的点的集合一定是一条自上而下的链,且这条链开头不定,但结尾一定是被修改点。

然后我们还可以发现(此处记 \(sum_i\) 表示 \(i\) 点的三个儿子中,权值为 \(1\) 的点得个数):

  • 若被修改点是从 \(1\) 改成 \(0\) 的,那么从被修改点开始向上,只有 \(sum=2\) 的点的颜色改变(从 \(1\) 变成 \(0\))。
  • 若被修改点是从 \(0\) 改成 \(1\) 的,那么从被修改点开始向上,只有 \(sum=1\) 的点的颜色改变(从 \(0\) 变成 \(1\))。

那么,求出一个点子树内最深的 \(sum \ne 1\) 或 \(sum \ne 2\) 的点即为修改这个点的子树内的叶子节点的链头。

那么怎么维护?

\(\mathcal O(n \log^3 n)\)

考虑树链剖分,用线段树维护区间最小值和最大值,当且仅当某个区间的最小值和最大值均为 \(1\) 或 \(2\) 时才表示这一链的点的权值均为 \(1\) 或 \(2\)。

至于链头,则可以通过二分或倍增来找,总时间复杂度为 \(\mathcal O(n \log^3 n)\)。

具体地,二分 \(\mathcal O(\log n)\),跳重链 \(\mathcal O(\log n)\),线段树查询 \(\mathcal O(\log n)\)。

\(\mathcal O(n \log^2 n)\)

LCT 可以 \(\mathcal O(\log n)\) 实现查询链上最大最小值。

故总时间复杂度优化为 \(\mathcal O(n \log^2 n)\)。

\(\mathcal O(n \log n)\)

考虑更直接的方法,维护一个点的信息。

讨论一下,修改 push_uppush_down 函数即可。

总时间复杂度为 \(\mathcal O(n \log n)\)。

许多细节。

具体参考代码。

#include <bits/stdc++.h>

#define lc c[x][0]
#define rc c[x][1]

using namespace std;

inline int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-')
            f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
        x = x * 10 + c - '0', c = getchar();
    return x * f;
}

const int _ = 1.5e6 + 10;

struct LCT
{
	int f[_], c[_][2], id[_][3], v[_], s[_], st[_];
	int lz[_];
	inline bool isroot(int x)
	{
		return c[f[x]][0] == x || c[f[x]][1] == x;
	}
	inline void push_up(int x)
	{
		id[x][1] = id[rc][1];
		id[x][2] = id[rc][2];
		if(!id[x][1])
		{
			if(s[x] != 1)
				id[x][1] = x;
			else
				id[x][1] = id[lc][1];
		}
		if(!id[x][2])
		{
			if(s[x] != 2)
				id[x][2] = x;
			else
				id[x][2] = id[lc][2];
		}
	}
	inline void push_(int t, int x)
	{
		s[t] += x, v[t] = s[t] > 1;
		swap(id[t][1], id[t][2]);
		lz[t] += x;
	}
	inline void push_down(int x)
	{
		if(lz[x])
		{
			if(lc)
				push_(lc, lz[x]);
			if(rc)
				push_(rc, lz[x]);
			lz[x] = 0;
		}
	}
	inline void rotate(int x)
	{
		int y = f[x], z = f[y], k = c[y][1] == x, w = c[x][!k];
		if(isroot(y))
			c[z][c[z][1] == y] = x;
		c[x][!k] = y, c[y][k] = w;
		if(w)
			f[w] = y;
		f[y] = x, f[x] = z;
		push_up(y);
	}
	inline void splay(int x)
	{
		int y = x, z = 0;
		st[++z] = y;
		while(isroot(y))
			st[++z] = y = f[y];
		while(z)
			push_down(st[z--]);
		while(isroot(x))
		{
			y = f[x], z = f[y];
			if(isroot(y))
				rotate((c[y][0] == x) ^ (c[z][0] == y) ? x : y);
			rotate(x);
		}
		push_up(x);
	}
	inline void access(int x)
	{
		for(int y = 0; x; x = f[y = x])
			splay(x), rc = y, push_up(x);
	}
} tr;

int n, m;

#define pr printf

int tot, head[_], to[_ << 1], nxt[_ << 1];

void add(int u, int v)
{
	to[++tot] = v, nxt[tot] = head[u], head[u] = tot;
}

void dfs(int x, int f)
{
	tr.s[x] = 0;
	for(int i = head[x], v; i; i = nxt[i])
	{
		v = to[i];
		if(v == f) continue;
		dfs(v, x);
		tr.s[x] += tr.v[v];
	}
	if(x <= n)
		tr.v[x] = tr.s[x] > 1;
}

signed main()
{
	n = read();
	int x;
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= 3; ++j)
		{
			x = read();
			tr.f[x] = i;
			add(x, i), add(i, x);
		}
	for(int i = n + 1; i <= n * 3 + 1; ++i)
		tr.v[i] = read();
	dfs(1, 0);
	m = read();
	int lst, w, addtag, ans = tr.v[1];
	while(m--)
	{
		lst = read(), x = tr.f[lst];
		addtag = tr.v[lst] ? -1 : 1;
		tr.access(x), tr.splay(x);
		w = tr.id[x][tr.v[lst] ? 2 : 1];
		if(w)
		{
			tr.splay(w);
			tr.push_(tr.c[w][1], addtag);
			tr.push_up(w);
			tr.s[w] += addtag, tr.v[w] = tr.s[w] > 1;
			tr.push_up(w);
		}
		else
		{
			ans ^= 1;
			tr.push_(x, addtag);
			tr.push_up(x);
		}
		tr.v[lst] ^= 1;
		pr("%d\n", ans);
	}
	return 0;
}

标签:log,修改,int,up,push,三叉神经,SHOI2014,mathcal,P4332
来源: https://www.cnblogs.com/orzz/p/16099327.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有