首页 > 其他分享 >【边分治】P4565 [CTSC2018] 暴力写挂

【边分治】P4565 [CTSC2018] 暴力写挂

时间:2023-09-19 22:22:39浏览次数:46  
标签:cur val P4565 int void 分治 son fa CTSC2018

初涉边分治。

大致就是按照一条边的两端来分类出两套点,然后对这个进行分治,有点是只用考虑两类集合,考虑贡献很简单!!反正就是比点分强。

但是如果直接分治是假的,会被菊花图薄纱,需要进行对树的三度化,这个是左儿子右兄弟,但是貌似很少人叫这个,比较不适,然后我们就可以做了。

建出来的边分树按照这个想法就是一颗二叉树,这个题考虑式子求二分之一,然后考虑边分树合并即可。

https://blog.csdn.net/cqbzlydd/article/details/128506334 大概是这样子。我抄袭题解。

int ecnt = 1, rte, all, msz;
int hd[___], sz[___], rdp[___];
ll dep[___], prv[___];

void addedge (int x, int y, int w) {
	e[++ ecnt] = {hd[x], y, w};
	hd[x] = ecnt;
}
void dfs1 (int x, int fa) {
	for (int i = hd[x]; i; i = e[i].nxt) {
		int y = e[i].y;
		if (y == fa) continue ;
		rdp[y] = rdp[x] + 1, 
		dep[y] = dep[x] + e[i].w;
		dfs1(y, x);
	}	
}
void dfs2 (int x, int fa) {
	all ++;
	for (int i = hd[x]; i; i = e[i].nxt) {
		int y = e[i].y;
		if (e[i].vis || (y == fa)) continue ;
		dfs2(y, x);
	}
}
void findrt (int x, int fa) {
	sz[x] = 1;
	for (int i = hd[x]; i; i = e[i].nxt) {
		int y = e[i].y;
		if (e[i].vis || (y == fa)) continue ;
		findrt(y, x);
		sz[x] += sz[y];
		int cur = abs(all - 2 * sz[y]);
		if (cur < msz) msz = cur, rte = i;
	}
}
void dfs3 (int x, int fa, int dir) {
	if (x <= n) {
		int cur = ++ nd;
		val[cur] = dep[x] + prv[x];
		son[rt[x]][dir] = cur;
		rt[x] = cur;
	}
	for (int i = hd[x]; i; i = e[i].nxt) {
		int y = e[i].y;
		if (e[i].vis || (y == fa)) continue ;
		prv[y] = prv[x] + e[i].w;
		dfs3(y, x, dir);
	}
}
void solve (int x) {
	all = 0;
	dfs2(x, 0);
	if (all == 1) return ;
	msz = 1e9, findrt(x, 0);
	int u = e[rte].y, v = e[rte ^ 1].y;
	e[rte].vis = e[rte ^ 1].vis = 1;
	prv[u] = e[rte].w, prv[v] = 0;
	dfs3(u, 0, rdp[u] > rdp[v]), dfs3(v, 0, rdp[v] > rdp[u]);
	solve(u), solve(v); 
}
int merge (int x, int y) {
	if (!x || !y) return x | y;
	if (son[x][0] && son[y][1]) 
		res = max(res, val[son[x][0]] + val[son[y][1]]);
	if (son[x][1] && son[y][0])
		res = max(res, val[son[x][1]] + val[son[y][0]]);
	val[x] = max(val[x], val[y]);
	son[x][0] = merge(son[x][0], son[y][0]),
	son[x][1] = merge(son[x][1], son[y][1]);
	return x;
}
void rebuild (int x, int fa) {
	int lst = x;
	for (auto & [y, w] : tr[x]) {
		if (y == fa) continue ;
		int cur  = ++ ndc;
		t1::addedge(lst, cur, 0), t1::addedge(cur, lst, 0);
		t1::addedge(cur, y, w), t1::addedge(y, cur, w);
		rebuild(y, x);
		lst = cur;
	}
}

放出部分屎山代码供参考。

我大致讲一下 Implement 是怎么样的。考虑像点分一样找出一条归类后差小的边。然后按照原树上的深度上归类出两类点。

边分树显然就是按照一些根来归类,然后一步一步走下来的链,然后我们可以按照这个来做到一个枚举边分树上的前缀和的一个效果。

便于实现,写几点吧:

  • 把 \(rt_x\) 设为 \(x\),便于走下去。

  • 都什么年代,还在写传统点分?

int cur = abs(all - 2 * sz[y]);
  • 使用类似网络流的成对存储。

  • 三度化写左儿子右兄弟的时候要注意虚点没有贡献的问题。

标签:cur,val,P4565,int,void,分治,son,fa,CTSC2018
From: https://www.cnblogs.com/Custlo/p/17715989.html

相关文章

  • 简单分治快排问题解析(c++实现)
    这几天刷了需要使用分治快排思想去解决的几道比较好的题目,所以写下这篇博客用于复习和以后的复盘。什么是分治快排思想首先我们要知道什么是分治快排思想,这个思想其实就是在模拟实现qsort算法的时候使用的一个方法,在模拟实现qsort的时候,我们知道第一步是需要使用一个随意选择(三数取......
  • 【学习笔记】(26) cdq 分治 与 整体二分
    cdq分治基本思想我们要解决一系列问题,这些问题一般包含修改和查询操作,可以把这些问题排成一个序列,用一个区间[L,R]表示。分。递归处理左边区间\([L,M]\)和右边区间\([M+1,R]\)的问题。治。合并两个子问题,同时考虑到\([L,M]\)内的修改对\([M+1,R]\)内的查询产生的影......
  • 可持久化非确定状态AC自动分块维护线段平衡仙人掌优化最小费用最大流预处理混合图上莫
    P8946TheLostSymbol这种类型的dp的特点就是大部分转移形如\(f(i,j)\rightarrowf(i+1,j+1)\)之类的,并且当以上转移出现时原数组被清空,这就可以用一个deque来维护,然后对于全局赋值/全局加,需要对每个位置维护一个时间戳,并记录上一次赋值/加是什么时候,以便标记下传。(貌似......
  • F. Remainder Problem 根号分治
    Problem-F-Codeforces 题意:一个500000长度的数列,一开始都是0,进行q次操作,操作如下1,输入x,y,令a[x]+=y。2,输入x,y,输出对于sum(a[idx]),idx的条件是idx=x%y。做法:如果我们模拟做,那么第一种操作就是o(1),第二种操作就是o(n)。我们换种想法,建立一个二维数组b[x][y],表......
  • 练习:分治算法--有序数组寻找中位数
    题:给定两个长度为m和n有序组数array1和array2,请找出这个有序数组的中位数。'''eg.[1,3]和[5,6],中位数是4[1,2,5,8,9]和[2,3,4,5],中位数是4'''###直接方法,使用内置排序函数sort#时间复杂度最高:O((n+m)log(n+m)),空间复杂度:O(n+m)1classSolution(object):2deff......
  • 分治算法学习
    思路分析:先找根(最大值)分为左右子树,转化为构建最大的左右子树,很明显,这里需要用到递归算法实现#include<bits/stdc++.h>usingnamespacestd;intnums[1001];voidconstructMaxTree(intarr[],intl,intr){ if(l>=r){ cout<<arr[l]<<""; return; } //找到最......
  • 点分治入门
    点分治,顾名思义,对树上的节点进行分治。其实就是把一棵树拆成几棵分别处理。要把一棵树分成几棵怎么做?显然选一个节点做根节点,分出它的子树就行。不难发现,这个点的选取对时间复杂度影响很大,去一个极端例子:一条链如果选取1,5号节点,时间复杂度是O(n),而如果选取3号节点,时间复杂度是......
  • 根号分治
    块状思想自学目录块状思想自学一些定义:引入为什么要有分块思想?A.分块思想:例题引入:思路引导ac代码:一些总结:一些小练习:(题解晚点写出来)一些定义:分块的基本思想是,通过对原数据的适当划分,并在划分后的每一个块上预处理部分信息,从而较一般的暴力算法取得更优的时间复杂度。分块的时......
  • 递归与分治
    递归递归的基本思想是某个函数直接或者间接地调用自身,这样原问题的求解就转换为了许多性质相同但是规模更小的子问题。求解时只需要关注如何把原问题划分成符合条件的子问题,而不需要过分关注这个子问题是如何被解决的。递归代码最重要的两个特征:结束条件和自我调用。自我调用是......
  • Educational Codeforces Round 152 (Rated for Div. 2)E. Max to the Right of Min(数
    题目链接:https://codeforces.com/problemset/problem/1849/E 大致题意: 长度为n的序列,求有多少个区间满足区间最大值在区间最小值的右边? 解题思路: (此题有使用线段树等其他做法,本处使用的是单调栈做法) 我们先求出每个a【i】的左边的比他小的LMIN,左边比他大的LMAX,右......