列表

详情


NC14649. 不存在的树

描述

kotomi 有一棵树。树上有n个房子,编号1-n,每个房子有一个快乐值。
kotomi想知道从a房子到b房子路径上的最大快乐值或者路径山疙瘩快乐值的和。
并且kotomi可以改变任意一个房子的快乐值。
具体如下
(1) 0 a b:查询a到b路径上的最大快乐值(包含a和b)
(2) 1 a b:查询a到b路径上的所有房子快乐值的和。(包含a和b)
(3) 2 x y:将编号为x的房子的快乐值改为y。

输入描述

多组测试数据
第一行有两个整数n,q。表示有n个房子,q次操作。
第二行有n个整数v1,v2...vn,表示编号为i的房子的快乐值vi
接下来n-1行,每行两个整数u,v,表示编号为u和编号为v的房子之间有一条直接路径。
接下来p行,每行开头一个整数(0,1或2)表述操作类型,每个操作后有两个整数。

输出描述

对于操作为0和1的输出对应的值。

示例1

输入:

6 10
2 5 9 10 36 5
1 2
1 3
1 4
2 5
2 6
0 1 4
0 1 6
1 5 6
1 3 6
1 6 3
2 3 10
1 5 3
0 4 5
2 5 100
1 5 4

输出:

10
5
46
21
21
53
36
117

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 678ms, 内存消耗: 15664K, 提交时间: 2020-07-30 11:14:53

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const int N=30303,mn=-1e9;
int a[N];
int child[N*2],pre[N*2],now[N];
int size[N],mx[N],f[N],dep[N];
int top[N],dfn[N],idfn[N];
int n,m,tot,t;
struct AC{
	int sum,mx;
}tree[N*8];
void ad(int x,int y){
	pre[++tot]=now[x];
	child[tot]=y;
	now[x]=tot;
}
void dfs1(int x,int rt){
	size[x]=1;
	for (int i=now[x]; i; i=pre[i]){
		int son=child[i];
		if (son==rt)	continue;
		dep[son]=dep[x]+1;
		f[son]=x;
		dfs1(son,x);
		size[x]=size[x]+size[son];
		if (size[mx[x]]<size[son])	mx[x]=son;
	}
}
void dfs2(int x,int rt){
	top[x]=rt;
	dfn[x]=++t,idfn[t]=x;
	if (mx[x])	dfs2(mx[x],rt);
	for (int i=now[x]; i; i=pre[i]){
		int son=child[i];
		if (f[x]==son||mx[x]==son)	continue;
		dfs2(son,son);
	}
}
AC update(AC x,AC y){
	return (AC){x.sum+y.sum,max(x.mx,y.mx)};
}
void build(int p,int l,int r){
	if (l==r){
		tree[p].mx=tree[p].sum=a[idfn[l]];
		return;
	}
	int mid=(l+r)>>1;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
	tree[p]=update(tree[p*2],tree[p*2+1]);
}
void modify(int p,int l,int r,int a,int b){
	if (l==r){
		tree[p].mx=tree[p].sum=b;
		return;
	}
	int mid=(l+r)>>1;
	if (a<=mid)	modify(p*2,l,mid,a,b);
	else modify(p*2+1,mid+1,r,a,b);
	tree[p]=update(tree[p*2],tree[p*2+1]);
}
AC find(int p,int l,int r,int a,int b){
	if (a<=l&&r<=b)	return tree[p];
	int mid=(l+r)>>1;
	AC f1=(AC){0,mn},f2=(AC){0,mn};
	if (a<=mid)	f1=find(p*2,l,mid,a,b);
	if (b>mid)	f2=find(p*2+1,mid+1,r,a,b);
	return update(f1,f2);
}

AC query(int x,int y){
	AC ans=(AC){0,mn};
	while (top[x]!=top[y]){
		if (dep[top[x]]<dep[top[y]])	swap(x,y);
		ans=update(ans,find(1,1,n,dfn[top[x]],dfn[x]));
		x=f[top[x]];
	}
	if (dep[x]<dep[y])	swap(x,y);
	return update(ans,find(1,1,n,dfn[y],dfn[x]));
}
int main(){
	int o,x,y;
	while (scanf("%d%d",&n,&m)!=EOF){
		tot=t=0;
		for (int i=1; i<=n; i++)	mx[i]=now[i]=0;
		for (int i=1; i<=n; i++)
			scanf("%d",&a[i]);
		for (int i=1; i<n; i++){
			scanf("%d%d",&x,&y);
			ad(x,y);
			ad(y,x);
		}
		dfs1(1,0);
		dfs2(1,1);
		build(1,1,n);
		for (int i=1; i<=m; i++){
			scanf("%d%d%d",&o,&x,&y);
			if (o==0)	printf("%d\n",query(x,y).mx);
			if (o==1)	printf("%d\n",query(x,y).sum);
			if (o==2)	modify(1,1,n,dfn[x],y);
		}
	}
	return 0;
}

上一题