首页 > 其他分享 >P4679 题解

P4679 题解

时间:2022-10-22 19:55:40浏览次数:86  
标签:lrd 树剖 int 题解 爆切 dfn P4679 dis

前言

题目传送门!

更好的阅读体验?

大力树剖!

做树剖时,大家可以膜拜 @liruiduan2 巨佬,他可以在考场上码 200 行的树剖题目。

思路

代码

有点长。可以用这份代码对拍。

/*树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖树剖*/
/*lrd爆切树剖lrd爆切树剖lrd爆切树剖lrd爆切树剖lrd爆切树剖lrd爆切树剖lrd爆切树剖lrd爆切树剖lrd爆切树剖*/
#include <iostream>
#include <cstdio>
#include <cstring>
#define space putchar(' ')
#define endl putchar('\n')
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef long double LD;
namespace io { //快读快写,可以直接忽略
	void fastio()
	{
		ios::sync_with_stdio(false);
		cin.tie(0), cout.tie(0);
	}
	inline int read()
	{
		char op = getchar(); int x = 0, f = 1;
		while (op < 48 || op > 57) {if (op == '-') f = -1; op = getchar();}
		while (48 <= op && op <= 57) x = (x << 1) + (x << 3) + (op ^ 0x30), op = getchar();
		return x * f;
	}
	inline void write(int x)
	{
		if (x < 0) putchar('-'), x = -x;
		if (x > 9) write(x / 10);
		putchar(x % 10 + 0x30);
	}
} using namespace io;
const int N = 5e4 + 5;
struct Edge
{
	int now, nxt;
} e[N << 1];
int head[N], cur;
inline void add(int u, int v) //链式前向星
{
	e[++cur].now = v;
	e[cur].nxt = head[u];
	head[u] = cur;
}
int siz[N], wson[N], fa[N], dep[N];
void dfs(int u) //树剖两次 dfs
{
	siz[u] = 1, dep[u] = dep[fa[u]] + 1;
	for (int i = head[u]; i; i = e[i].nxt)
	{
		int v = e[i].now;
		if (v != fa[u])
		{
			fa[v] = u;
			dfs(v);
			siz[u] += siz[v];
			if (wson[u] == 0 || siz[v] > siz[wson[u]]) wson[u] = v;
		}
	}
}
int top[N];
bool map[N][2], zlt[N][2]; //zlt : 转化为dfn的地图 
int dfn[N], vist;
void DFS(int u, int frt)
{
	dfn[u] = ++vist;
	top[u] = frt;
	zlt[vist][0] = map[u][0], zlt[vist][1] = map[u][1];
	if (wson[u] == 0) return;
	DFS(wson[u], frt);
	for (int i = head[u]; i; i = e[i].nxt)
	{
		int v = e[i].now;
		if (v != fa[u] && v != wson[u]) DFS(v, v);
	}
}
struct Node
{
	int lmx[2], rmx[2], dis[2][2];
	Node() {lmx[0] = lmx[1] = rmx[0] = rmx[1] = dis[0][0] = dis[0][1] = dis[1][0] = dis[1][1] = 0;}
	inline void create(bool a[]) //创建一个新节点
	{
		int d = 2, x = a[0], y = a[1];
		const int inf = 0x3f3f3f3f;
		if (!x) d = x = -inf;
		if (!y) d = y = -inf;
		lmx[0] = rmx[0] = max(x, 0), lmx[1] = rmx[1] = max(y, 0);
		dis[0][0] = x, dis[1][1] = y;
		dis[0][1] = dis[1][0] = d;
	}
} s[N << 2];
inline Node operator +(const Node &x, const Node &y) //合并两个节点
{
	Node a;
	for (int i = 0; i <= 1; i++)
		for (int j = 0; j <= 1; j++)
		{
			a.lmx[i] = max(a.lmx[i], max(x.lmx[i], x.dis[i][j] + y.lmx[j]));
			a.rmx[i] = max(a.rmx[i], max(y.rmx[i], y.dis[j][i] + x.rmx[j]));
			a.dis[i][j] = -0x3f3f3f3f; //类似 floyd 的写法
			for (int k = 0; k <= 1; k++) a.dis[i][j] = max(a.dis[i][j], x.dis[i][k] + y.dis[k][j]);
		}
	return a;
}
struct SegmentTree //线段树
{
	inline int ls(int x) {return x << 1;}
	inline int rs(int x) {return x << 1 | 1;}
	inline void pushup(int pos) {s[pos] = s[ls(pos)] + s[rs(pos)];}
	void build(int l, int r, int pos)
	{
		if (l == r) return s[pos].create(zlt[l]);
		int mid = (l + r) >> 1;
		build(l, mid, ls(pos));
		build(mid + 1, r, rs(pos));
		pushup(pos);
	}
	void update(int l, int r, int pos, int id, bool a[])
	{
		if (l == r) return s[pos].create(a);
		int mid = (l + r) >> 1;
		if (id <= mid) update(l, mid, ls(pos), id, a);
		else update(mid + 1, r, rs(pos), id, a);
		pushup(pos);
	}
	Node query(int l, int r, int pos, int L, int R) //warning: 由于空节点与非空节点合并会挂,所以要分开写 
	{
		if (L <= l && r <= R) return s[pos];
		int mid = (l + r) >> 1;
		/*我平时的写法
		Node ans;
		if (L <= mid) ans = ans + query(l, mid, ls(pos), L, R);
		if (mid < R) ans = ans + query(mid + 1, r, rs(pos), L, R);
		return ans;
		*/
		if (L > mid) return query(mid + 1, r, rs(pos), L, R); //没有 L<=mid 说明有 mid<R 
		if (mid >= R) return query(l, mid, ls(pos), L, R); //没有 mid<R 说明有 L<=mid
		return query(l, mid, ls(pos), L, R) + query(mid + 1, r, rs(pos), L, R); //两个非空节点合并才不会挂 
	}
} seg;
int n;
struct Tree //大力树剖!
{
	void Swap(Node &a) //把当前点翻转 
 	{
		for (int i = 0; i <= 1; i++) swap(a.lmx[i], a.rmx[i]);
		swap(a.dis[0][1], a.dis[1][0]);
	}
	int query(int x, int y)
	{
		Node nx, ny;
		while (top[x] != top[y]) //下面注意要写成 nx = query + nx,因为空节点合并会有问题
		{
			if (dep[top[x]] > dep[top[y]])
					nx = seg.query(1, n, 1, dfn[top[x]], dfn[x]) + nx, x = fa[top[x]];
			else 	ny = seg.query(1, n, 1, dfn[top[y]], dfn[y]) + ny, y = fa[top[y]];
		}
		
		if (dep[x] > dep[y]) nx = seg.query(1, n, 1, dfn[y], dfn[x]) + nx;
		else ny = seg.query(1, n, 1, dfn[x], dfn[y]) + ny;
		Swap(nx);
		Node ans = nx + ny;
		return max(ans.lmx[0], ans.lmx[1]);
	}
} tree;
int main()
{
	n = read(); int T = read();
	for (int i = 1; i < n; i++)
	{
		int u = read(), v = read();
		add(u, v), add(v, u);
	}
	for (int i = 1; i <= n; i++)
	{
		char s[2]; scanf("%s", s);
		map[i][0] = (s[0] == '.'), map[i][1] = (s[1] == '.');
	}
	dfs(1), DFS(1, 1);
	seg.build(1, n, 1);
	while (T--)
	{
		char op[2];
		scanf("%s", op);
		if (op[0] == 'C')
		{
			int i = read();
			char s[2]; scanf("%s", s);
			map[i][0] = (s[0] == '.'), map[i][1] = (s[1] == '.'); //暴力更新
			seg.update(1, n, 1, dfn[i], map[i]);
		}
		else
		{
			int u = read(), v = read();
			write(tree.query(u, v)), endl;
		}
	}
	return 0;
}
/*
hack
5 1
4 5
2 5
4 3
4 1
..
#.
#.
#.
##
Q 2 4
*/

希望能帮助到大家!

标签:lrd,树剖,int,题解,爆切,dfn,P4679,dis
From: https://www.cnblogs.com/liangbowen/p/16817148.html

相关文章

  • P2218 题解
    前言题目传送门!更好的阅读体验?二分答案套搜索。思路答案显然具有单调性,于是可以二分答案。问题是如何实现\(\operatorname{check}(k)\)函数(\(k\)指薄膜边长)。其......
  • 洛谷P2827题解
    原题P2827[NOIP2016提高组]蚯蚓思路概述题意分析给定整数\(n,m,q,u,v,t\)和一个数列\(\{a\}\),进行\(m\)次操作如下:每次选取其中最大数\(x\)切分为\([px],x......
  • dremio 21 版本之后反射No File System scheme matches 问题解决
    实际属于一个老问题了,整理下,方便使用,主要是我们在使用反射的时候碰到的问题问题如下UnknownFormatConversionException:Conversion='Unknownformat(pdfs)conversio......
  • CodeForces-1143#C 题解
    正文♦时间复杂度:\(\mathcal{O}(n)\)思维题,不需要建树。设数组\(a\)记录每一个节点是否尊重它的父节点,数组\(b\)记录是否有节点尊重它,特别的,叶子节点必然不被尊重。......
  • [题解]如何求连续区间最大和
    给一个数列,有正有负,如何求最大的连续区间和?需要设f数组表示每个位置为结尾的最大区间和能否让f[i]等于f[i-1]+a[i]要看这样的f[i]是否大于零如果大于0,就说明它仍然可以......
  • 「题解」洛谷 P8529 [Ynoi2003] 赫露艾斯塔
    构造半平面莫队?/jk注意到对于一个半平面的直线,通过平移和旋转经过的点数,一定大于等于它们的对称差,因为对称差中的点会被经过奇数次,不在对称差中的点会被经过偶数次。那么......
  • ABC266 ~ 273 题解
    缺省源#pragmaGCCoptimize(3)#include<bits/stdc++.h>namespace//tofoldthatjunkcode{#definefilein(x){freopen(x".in","r",stdin);}#definefile(......
  • Fabricating Sculptures 题解
    草草地写一篇题解,废话不多说暴力要拼成“^”型,考虑\(DP\)令\(f_{i,j}\)表示,总共有\(i\)个积木,其中底座占了\(j\)个积木,也就是说你还有\(i-j\)个积木来拼底座的......
  • CF1716C Robot in a Hallway题解
    \(2000\)分的DP题。题意给定一个\(2\)行\(n\)列的网格。机器人初始坐标为\((0,1)\),每一秒都可以向四周移动。每个格子有解锁时间,在该时间之前机器人不可以进入该......
  • CF1045G 题解
    前言题目传送门!更好的阅读体验?和模版稍有不同的cdq分治。思路cdq是离线算法,所以我们可以先给\(x_i\)离散化一下。同时,记录下\((x_i-r_i)\)与\((x_i+r_i)......