抽象的題目(咱就是說,這個”難存的情緣“是指要把礦掏空嗎)
題目
分析
這個題目還是比較好理解的,我們需要乾的有 \(2\) 個操作,但實際上有 \(3\) 個
- 1 :邊權轉點權
- 2 :單點修改
- 3 :鏈上最大值查詢
很明顯是樹刨板子題,操作中需要注意的有三點,如何轉邊權,最大值點權查多了,修改時的邊與點的對應
點券轉邊權
還是很好處理的,在 \(dfs\) 預處理時將邊權存一下即可,就是熒光筆標註的這行
最大值查詢
根據上面的程式碼,我們發現,邊權存在邊上深度較大的那個點上,這就會導致一個問題,如圖
假設我們求 \(3-4\) 這條路上的最大值,那實際上我們在樹上找的是 \(3-2-4\) 這條路上的點權最大值,很顯然,我們要找
紅色的邊,但操作上卻多了一條綠色的邊。。。真雞肋啊.
那我們如何解決呢,我們簡單推廣一下可以發現,實際上多的邊就是求得兩點的 \(lca\) 的值,也就是鏈上深度最小的點
這樣就很顯然了,只要在求解時,在指標跳到同一條重鏈以後,求深度小的點加一到深度大的點的值即可
還是熒光筆標的這一行。。。
對應
這個問題還是困擾了我七七 \(=10\) 分鐘的,當時一直在想 \(1e5\) 的邊,那求邊和邊的關係那不得開個 \(1e10\) 的陣列嗎
這不炸我***,所以 \(pass\) 了啊,然後就突然想到了(我覺得是發呆後的靈光乍現),直接在連結串列儲存的時候多開一個
\(id\),這個陣列存的實際上就是這個邊的編號,還是在 \(dfs\) 預處理時,新開一個對應陣列 \(dian\),下標是邊號,存的是點
號,對應一下就行了,依舊是熒光筆標註的這行
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;
}