CF1916E Happy Life in University

目录

tags

枚举 线段树

中文题面

给定 n n n 个点、点 u u u 有颜色 a u a_u au 的树,定义 f ( u , v ) f(u, v) f(u,v) 为 u → v u \to v u→v 的路径上的颜色数目, u u u 不是 v v v 祖先时无定义。对于所有点对 ( u , v ) (u,v) (u,v),其中 u u u 不一定相异于 v v v,设 l l l 为 u , v u, v u,v 的最近公共祖先,求 max ⁡ { f ( l , u ) ⋅ f ( l , v ) } \max\{ f(l, u) \cdot f(l, v) \} max{f(l,u)⋅f(l,v)}。

多测, 1 ≤ ∑ n ≤ 3 ⋅ 1 0 5 , 1 ≤ a i ≤ n , 1 ≤ p i ≤ i − 1 1 \leq \sum n \leq 3 \cdot 10^5, 1 \leq a_i \leq n, 1 \leq p_i \leq i-1 1≤∑n≤3⋅105,1≤ai≤n,1≤pi≤i−1。

第一行输入 t t t 表示数据组数。对于每组数据,第一行输入 n n n,第二行输入 n − 1 n-1 n−1 个数 p 2 ∼ p n p_2 \sim p_n p2∼pn, p i p_i pi 为 i i i 的父亲的编号,第三行输入 n n n 个数 a 1 ∼ a n a_1 \sim a_n a1∼an 表示编号为 i i i 的点的颜色。

对于每组数据,输出一行一个数字,表示 max ⁡ { f ( l , u ) ⋅ f ( l , v ) } \max\{ f(l, u) \cdot f(l, v) \} max{f(l,u)⋅f(l,v)}。

思路

考虑枚举 l c a lca lca,找出每个子树中叶子到 l c a lca lca 路径颜色数的最大值 [ m a x ] [max] [max]、次大值 [ m i n ] [min] [min],则该子树答案为

a n s = [ m a x ] ∗ [ m i n ] ans = [max] * [min] ans=[max]∗[min]

问题转化为动态维护路径的颜色数最大值,可以用线段树来解决。

从叶子节点出发,每次直接给子树 + 1 +1 +1,注意在算重的位置减去贡献即可。

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define A(x,y) x=(x+y)%mod
#define N 3e5 + 5
const int M = N<<2, mod = 998244353;
int T,n,c[N],p[N],dfn[N],low[N],tot, asw;vector<int>v[N],s[N];
struct tree{
	int l[M],r[M],tag[M],ma[M];
	#define ls (k<<1)
	#define rs (k<<1|1)
	void Pd(int k,int v){
		tag[k]+=v;
		ma[k]+=v;
	}
	void pd(int k){
		tag[k]&&(Pd(ls,tag[k]),Pd(rs,tag[k]),tag[k]=0);
	}
	void pu(int k){
		ma[k]=max(ma[ls],ma[rs]);
	}
	void build(int L=1,int R=n,int k=1){
		l[k]=L,r[k]=R,tag[k]=ma[k]=0;
		if(L==R)return;
		int mid=L+R>>1;
		build(L,mid,ls),build(mid+1,R,rs);
	}
	void add(int L,int R,int v,int k=1){
		if(R<l[k]||r[k]<L)return;
		if(L<=l[k]&&r[k]<=R)return Pd(k,v);
		pd(k),add(L,R,v,ls),add(L,R,v,rs),pu(k);
	}
	int ask(int L,int R,int k=1){
		if(R<l[k]||r[k]<L)return 0;
		if(L<=l[k]&&r[k]<=R)return ma[k];
		return pd(k),max(ask(L,R,ls),ask(L,R,rs));
	}
}t;
void dfs(int u){int tmp=p[c[u]];s[tmp].push_back(u),p[c[u]]=u,dfn[u]=++tot;
	for(auto i:v[u])dfs(i);p[c[u]]=tmp,low[u]=tot;
}
void DFS(int u){
	for(auto i:v[u])DFS(i);int f1=1,f2=1;t.add(dfn[u],low[u],1);
	for(auto i:s[u])t.add(dfn[i],low[i],-1);
	for(auto i:v[u]){int f=t.ask(dfn[i],low[i]);
		if(f>f1)f2=f1,f1=f;else f2=max(f2,f);
	}
	asw=max(asw,1ll*f1*f2);
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>T;
	while(T--){
		cin>>n,asw=tot=0;
		for(int x,i=2;i<=n;i++)cin>>x,v[x].push_back(i);
		for(int i=1;i<=n;i++)cin>>c[i];
		dfs(1),t.build(),DFS(1);
		cout<<asw<<"\n";
		for(int i=0;i<=n;i++)v[i].clear(),s[i].clear();
	}
}
相关推荐
passer__jw76712 分钟前
【LeetCode】【算法】283. 移动零
数据结构·算法·leetcode
Ocean☾19 分钟前
前端基础-html-注册界面
前端·算法·html
顶呱呱程序27 分钟前
2-143 基于matlab-GUI的脉冲响应不变法实现音频滤波功能
算法·matlab·音视频·matlab-gui·音频滤波·脉冲响应不变法
爱吃生蚝的于勒1 小时前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
羊小猪~~1 小时前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
王哈哈^_^1 小时前
【数据集】【YOLO】【VOC】目标检测数据集,查找数据集,yolo目标检测算法详细实战训练步骤!
人工智能·深度学习·算法·yolo·目标检测·计算机视觉·pyqt
星沁城1 小时前
240. 搜索二维矩阵 II
java·线性代数·算法·leetcode·矩阵
脉牛杂德2 小时前
多项式加法——C语言
数据结构·c++·算法
legend_jz2 小时前
STL--哈希
c++·算法·哈希算法
CSUC2 小时前
【C++】父类参数有默认值时子类构造函数列表中可以省略该参数
c++