难存的情缘

抽象的题目(咱就是说,这个”难存的情缘“是指要把矿掏空吗)

题目

image

分析

这个题目还是比较好理解的,我们需要干的有 \(2\) 个操作,但实际上有 \(3\)

  • 1 :边权转点权
  • 2 :单点修改
  • 3 :链上最大值查询

很明显是树刨板子题,操作中需要注意的有三点,如何转边权,最大值点权查多了,修改时的边与点的对应

点券转边权

还是很好处理的,在 \(dfs\) 预处理时将边权存一下即可,就是荧光笔标注的这行

image

最大值查询

根据上面的代码,我们发现,边权存在边上深度较大的那个点上,这就会导致一个问题,如图

image

假设我们求 \(3-4\) 这条路上的最大值,那实际上我们在树上找的是 \(3-2-4\) 这条路上的点权最大值,很显然,我们要找

红色的边,但操作上却多了一条绿色的边。。。真鸡肋啊.

那我们如何解决呢,我们简单推广一下可以发现,实际上多的边就是求得两点的 \(lca\) 的值,也就是链上深度最小的点

这样就很显然了,只要在求解时,在指针跳到同一条重链以后,求深度小的点加一到深度大的点的值即可

image

还是荧光笔标的这一行。。。

对应

这个问题还是困扰了我七七 \(=10\) 分钟的,当时一直在想 \(1e5\) 的边,那求边和边的关系那不得开个 \(1e10\) 的数组吗

这不炸我***,所以 \(pass\) 了啊,然后就突然想到了(我觉得是发呆后的灵光乍现),直接在链表存储的时候多开一个

\(id\),这个数组存的实际上就是这个边的编号,还是在 \(dfs\) 预处理时,新开一个对应数组 \(dian\),下标是边号,存的是点

号,对应一下就行了,依旧是荧光笔标注的这行

image

solution

点击查看代码
#include<bits/stdc++.h>
#define lid id<<1
#define rid id<<1|1
const int maxn=1e5+10;
const int inf=0x7f7f7f7f;
using namespace std;
int n,t,a[maxn<<2];
struct node{int to,next,val,id;}e[maxn<<2];
struct tree{int maxx;}m[maxn<<4];
int tot,head[maxn];
int size[maxn],wson[maxn],fa[maxn],dep[maxn],top[maxn],dian[maxn];
int dfn[maxn],pre[maxn],cnt=0;
void add(int x,int y,int z,int i)
{
	e[++tot].to=y;
	e[tot].val=z;
	e[tot].id=i;
	e[tot].next=head[x];
	head[x]=tot;
}
void addm(int x,int y,int z,int i)
{
	add(x,y,z,i),add(y,x,z,i);
}
void dfs1(int u,int f)
{
	size[u]=1;
	for(int i=head[u];i;i=e[i].next)
	{
		int y=e[i].to;
		if(y==f)continue;
		dep[y]=dep[u]+1;
		dian[e[i].id]=y;
		a[y]=e[i].val;
		fa[y]=u;
		dfs1(y,u);
		size[u]+=size[y];
		if(size[y]>size[wson[u]])wson[u]=y; 
	}
}
void dfs2(int u,int topfa)
{
	dfn[u]=++cnt;
	pre[cnt]=u;
	top[u]=topfa;
	if(wson[u])dfs2(wson[u],topfa);
	for(int i=head[u];i;i=e[i].next)
	{
		int y=e[i].to;
		if(y==fa[u]||y==wson[u])continue;
		dfs2(y,y);
	}
}
void up(int id)
{
	m[id].maxx=max(m[lid].maxx,m[rid].maxx);
}
void build(int id,int l,int r)
{
	int mid=(l+r)>>1;
	if(l==r)
	{
		m[id].maxx=a[pre[l]];
		return ;
	}
	build(lid,l,mid);
	build(rid,mid+1,r);
	up(id);
}
void update(int id,int l,int r,int x,int y)
{
	if(l==r)
	{
		m[id].maxx=y;
		return ;
	}
	int mid=(l+r)>>1;
	if(x<=mid)update(lid,l,mid,x,y);
	else update(rid,mid+1,r,x,y);
	up(id);
}
int querymax(int id,int l,int r,int x,int y)
{
	int mid=(l+r)>>1,ans=-inf;
	if(x<=l&&r<=y)return m[id].maxx;
	if(x<=mid)ans=max(ans,querymax(lid,l,mid,x,y));
	if(y>mid)ans=max(ans,querymax(rid,mid+1,r,x,y));
	up(id);
	return ans;
}
int qmax(int x,int y)
{
	int ans=-inf;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		ans=max(ans,querymax(1,1,n,dfn[top[x]],dfn[x]));
		x=fa[top[x]]; 
	}
	if(dep[x]<dep[y])swap(x,y);
	ans=max(ans,querymax(1,1,n,dfn[y]+1,dfn[x]));
	return ans;
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		addm(x,y,z,i);
	}
	dfs1(1,0);
	dfs2(1,1);
	build(1,1,n);
	char ss[10];
	while(1)
	{
		int x,y;
		scanf("%s",ss+1);
		if(ss[1]=='D')break;
		scanf("%d%d",&x,&y);
		if(ss[1]=='Q')
		{
			printf("%d\n",qmax(x,y));
		}
		else
		{
//			cout<<endl<<dian[x]<<endl;
			update(1,1,n,dfn[dian[x]],y);
		}
	}
	
	return 0;
}

posted @ 2024-05-14 11:39  _君の名は  阅读(49)  评论(4编辑  收藏  举报