首页 > 其他分享 >【线段树合并】CF1805E There Should Be a Lot of Maximums 题解

【线段树合并】CF1805E There Should Be a Lot of Maximums 题解

时间:2023-10-05 22:47:17浏览次数:37  
标签:rt return Maximums val int 题解 There tr ls

CF1805E

待补:有另解

看到维护树上问题,可以想到线段树合并。

但直接维护显然不行,要一点技巧。

发现 \(val\) 的出现次数 \(cnt_{val}\) 如果 \(\ge 3\),那么一定是一个候选项,若 \(cnt_{val} = 1\),那么一定不能作为候选项。

于是可以用权值线段树维护对于 \(val\) 有 \(cnt_{val} = 2\) 的 \(val\)。先离散化,然后再合并线段树。查找时,若右子节点的 \(\max = 2\) 或右子节点的 \(\min = 0\),就递归查找右节点,反之亦然。若左右子节点都不满足,就返回 \(0\),实现需要一点细节。

空间只需要开 \(32\) 倍。

时间复杂度:\(\mathcal{O}(n\log n)\)。

代码:

const int N = 1e5 + 10;
int n, tot, maxv, mx, num;
int a[N], b[N], rt[N], ans[N];
int head[N], cnt;
map<int, int> mp;
struct segt {
	int ls, rs, mxv, mnv;
} tr[N << 5];
struct edge {
	int v, nxt, id;
} e[N << 1];

void adde(int u, int v, int id) {
	e[++cnt].v = v;
	e[cnt].nxt = head[u];
	e[cnt].id = id;
	head[u] = cnt;
}
void pushup(int u) {
	tr[u].mxv = max(tr[tr[u].ls].mxv, tr[tr[u].rs].mxv);
	tr[u].mnv = min(tr[tr[u].ls].mnv, tr[tr[u].rs].mnv);
}
void ins(int u, int l, int r, int k, int val) {
	if (l == r) {
		tr[u].mxv = tr[u].mnv = val;
		return;
	}
	int mid = l + r >> 1;
	if (k <= mid)
		ins(tr[u].ls = ++tot, l, mid, k, val);
	else
		ins(tr[u].rs = ++tot, mid + 1, r, k, val);
	pushup(u);
}
int merge(int lu, int ru, int l, int r) {
	if (!ru) return lu;
	if (!lu) return ru;
	if (l == r) {
		tr[lu].mxv += tr[ru].mxv;
		tr[lu].mnv += tr[ru].mnv;
		return lu;
	}
	int mid = l + r >> 1;
	tr[lu].ls = merge(tr[lu].ls, tr[ru].ls, l, mid);
	tr[lu].rs = merge(tr[lu].rs, tr[ru].rs, mid + 1, r);
	pushup(lu);
	return lu;
}
int query(int u, int l, int r) {
	if (l == r) {
		if (tr[u].mxv == 2 || tr[u].mnv == 0)
			return l;
		return 0;
	}
	int mid = l + r >> 1;
	if (tr[tr[u].rs].mxv == 2 || tr[tr[u].rs].mnv == 0)
		return query(tr[u].rs, mid + 1, r);
	if (tr[tr[u].ls].mxv == 2 || tr[tr[u].ls].mnv == 0)
		return query(tr[u].ls, l, mid);
	return 0;
}
void dfs(int u, int f, int pos) {
	rt[u] = ++tot;
	if (a[u])
		ins(rt[u], 1, num, a[u], 1);
	for (int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].v;
		if (v != f) {
			dfs(v, u, i);
			if (tr[rt[v]].mxv)
				rt[u] = merge(rt[u], rt[v], 1, num);
		}
	}
	if (tr[rt[u]].mxv == 0) {
		ans[e[pos].id] = max(mx, maxv);
		return;
	}
	int val = max(maxv, b[query(rt[u], 1, num)]);
	ans[e[pos].id] = val;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin >> n;
	for (int i = 1, u, v; i < n; i++) {
		cin >> u >> v;
		adde(u, v, i), adde(v, u, i);
	}
	for (int i = 1; i <= n; i++)
		cin >> a[i],
		mp[a[i]]++;
	for (auto it : mp) {
		if (it.second == 2) {
			b[++num] = it.first;
			mx = max(mx, it.first);
		} else if (it.second > 2)
			maxv = max(maxv, it.first);
	}
	for (int i = 1; i <= n; i++)
		if (mp[a[i]] != 2)
			a[i] = 0;
		else
			a[i] = lower_bound(b + 1, b + num + 1, a[i]) - b;
	dfs(1, 0, 0);
	for (int i = 1; i < n; i++)
		cout << ans[i] << "\n";
	return 0;
}

提供一组 hack:

输入:

10 
1 2
1 3
1 4
1 5
1 6
2 7
2 8
3 9
4 10
1 3 3 3 3 4 10 4 6 2

输出:

3
4
4
4
3
4
3
4
4

标签:rt,return,Maximums,val,int,题解,There,tr,ls
From: https://www.cnblogs.com/Pengzt/p/17744054.html

相关文章

  • [ABC257F] Teleporter Setting 题解
    1.题目洛谷传送门2.思路我们可以把不确定的点当成真实存在的\(0\)号点,建边的时候就正常连即可。然后我们来看一个样例:1-2-03-4-5当我们把\(0\)号点看成\(3\)号点时,答案就是\(1\)号点到\(0\)号点的距离加上\(3\)号点到\(5\)号点的距离。然后我们再......
  • 【思维】【DP】ABC298Ex Sum of Min of Length 题解
    ABC298Ex简单题。因为有\(\min\)不好做,容易想到讨论\(d(i,L)\)和\(d(i,R)\)的大小。令\(p=\text{LCA}(L,R)\),\(dep_L>dep_R,dist=dep_L+dep_R-2\timesdep_p\),\(now\)满足\(dep_L-dep_{now}=\lfloor\dfrac{dist}{2}\rfloor\)则\(L\)一定在......
  • 【图论】【寻找性质】CF1151E Number of Components 题解
    CF1151E发现每一个\(f(l,r)\)中的连通块总是一条链(一棵树)。那么此时连通块的数量就等于点的数量减去边的数量。先考虑点的总数,一个价值为\(a_i\)的点一定是在\(l\leqslanta_i\)且\(r\geqslanta_i\)的\(f(l,r)\)中才会有一个贡献,根据乘法原理,它会产生\(a_i\time......
  • 【二分】P7795 [COCI2014-2015#7] PROSJEK 题解
    P7795典。显然\(\mathcal{O}(n^2)\)的时间复杂度无法通过。使子段平均值最大,考虑二分。可以二分平均值\(mid\),然后判断是否有满足条件的子段.时间复杂度:\(\mathcal{O}(\dfrac{n\log\max\{a_i\}}{\text{eps}})\),其中\(\text{eps}\)为设置的精度,\(\max\{a_i\}\leq10......
  • P8565 Sultan Rage 题解
    P8565发现数列\(a\)增长的特别快,项数最多时是\(a_1=a_2=\cdots=a_{100}\),但这样也只会有一百多项就可以超过\(10^{18}\)。可以考虑搜索,因为搜索树会比较稀疏,函数dfs(val,cur)表示凑出\(x\)还需要\(val\),现在在考虑\(cur\)。但光是搜索肯定不能过这道题,考虑优......
  • P4133 [BJOI2012]最多的方案 题解
    P4133双倍经验发现斐波那契数列增长极快,不到\(100\)项就超过了\(10^{18}\),搜索树也极为稀疏,可以考虑搜索。爆搜肯定会超时,考虑优化:可行性剪枝。记忆化,去除重复的计算。改变搜索的顺序,因为先考虑小元素的话,会有较多的无用的搜索,且小元素较灵活,更容易凑到\(x\),故可......
  • 【竞赛图】【DP】ARC163D Sum of SCC 题解
    ARC163D发现这个竞赛图一定能被分为两个集合\(A\),\(B\)。满足\(\forallu\inA,v\inB\),均有\(u\tov\inE\)。答案就是划分这两个集合的方案数。证明:首先,竞赛图缩完点后一定是一条链,对强连通分量进行标号,满足编号小的强连通分量指向编号大的强连通分量。不妨令竞赛图\(G\)......
  • 【整除分块】【DP】ABC239Ex Dice Product 2 题解
    ABC239H简单题。令\(f_i\)表示乘到\(\gei\)的期望。容易得到\(f_i=\dfrac{\sum\limits_{j=1}^{n}f_{\lceil\frac{i}{j}\rceil}}{n}\)。将\(f_i\)移到同一边,去掉系数,有\(f_i=\dfrac{n\sum\limits_{j=2}^{n}f_{\lceil\frac{i}{j}\rceil}}{n-1}\)。提出\(\frac{n-1}{n......
  • 【字符串】【哈希】ABC284F ABCBAC 题解
    ABC284F这题的正解是\(Z\)函数。如果\(str=T+T\)的话,若可以找到连续的分别长为\(n\)的两段,且这两段可通过\(1\)次翻转变为相同的字符串,那么便一定有解,否则无解。暴力判断是\(\mathcal{O}(n)\)的,时间复杂度直接上天。可以用哈希\(\mathcal{O}(1)\)地判断出两个......
  • 【组合计数】ARC058D Iroha and a Grid 题解
    ARC058D简单组合计数。可以先把矩形旋转一下,变为求从\((1,1)\)走到\((n,m)\),只能向上或向右移动。且不经过左上角的\(A\timesB\)的禁区的方案数,对\(10^9+7\)取模。假如没有\(A\timesB\)的禁区的话,那么方案数为\(C_{n+m-2}^{n-1}\)。就是一共要走\(n+m-2\)......