難存的情緣

_君の名は發表於2024-05-14

抽象的題目(咱就是說,這個”難存的情緣“是指要把礦掏空嗎)

題目

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;
}

相關文章