目錄輸入輸出樣例
說明說明
思路ac**
總結p4114 qtree1
給定一棵 $ n $個節點的樹,有兩個操作:
change $ i $ $ t_i $ 把第 $ i $條邊的邊權變成 $ t_i $
query $ a $ $ b $ 輸出從 $ a $ 到 $ b $ 的路徑中最大的邊權,當 $ a=b $ 的時候,輸出 0
第一行輸入乙個 $ n $,表示節點個數
第二行到第 $ n $ 行每行輸入三個數,$ u_i,v_i,w_i $ ,分別表示 $ u_i,v_i $ 有一條邊,邊權是 $ w_i $
第 $ n+1 $ 行開始,一共有不定數量行,每一行分別有以下三種可能
change,query同題意所述
done表示輸入結束
對於每個query操作,輸出乙個數,表示 $ a $ $ b $ 之間邊權最大值
3
1 2 1
2 3 2
query 1 2
change 1 3
query 1 2
done
1
33
【資料範圍】
$1 \leq n \leq 10^5 $
操作次數 $ \leq 3*10^5 $
$ w_i $ 和 $ t_i \leq 2^-1$
【時空限制】
1000ms,512m
熟知的樹鏈剖分是解決點權的問題的,而這一題是邊權。
由於每個點可以有多個兒子,但只有乙個父親,可以考慮將邊權儲存到深度較大的點的點權。這樣n-1條邊的邊權就會對應到n-1個點上,而根節點(這裡以1為根節點)的點權就是0。
再考慮題中兩個操作。
change操作相對簡單。改變兩點之間的邊權,即改動兩點中較深點的點權。
query操作略有改動。查詢兩點間路徑中所有邊的最大邊權,如果查詢所有經過的點是有問題的。先看圖
其中while迴圈不用改變,while迴圈結束後,u和v處於同一條鏈上。
如果u==v,此時u和v都是最初兩點的lca,此時直接返回
否則,u和v之中深度較小的那一點是最初兩點的lca,應該從這個點的重兒子開始統計答案。
故改變後的**如下
int ask(int u,int v)
#includeconst int maxn=100010;
using namespace std;
int n,wt[maxn];
int tot,to[maxn<<1],nxt[maxn<<1],head[maxn];
int dep[maxn],len[maxn],fa[maxn],son[maxn];
int cnt,nid[maxn],nw[maxn],top[maxn];
struct segmenttree
tree[maxn<<2];
void dfs1(int u,int f,int d)
}void dfs2(int p,int t)
}void buildtree(int p,int l,int r)
buildtree(p<<1,l(p),m(p));
buildtree(p<<1|1,m(p)+1,r);
mx(p)=max(mx(p<<1),mx(p<<1|1));
}void change(int np,int p,int k)
if(p<=m(np)) change(np<<1,p,k);
if(p>m(np)) change(np<<1|1,p,k);
mx(np)=max(mx(np<<1),mx(np<<1|1));
}int q(int p,int l,int r)
int ask(int u,int v)
int main()
buildtree(1,1,n);
while(1)
if(way=="query")
}return 0;
}
樹剖處理邊權的板子題 洛谷P3384 樹鏈剖分
這是一道樹鏈剖分的模板題,首先要學會線段樹 dfs 鏈式前向星之類的,不然 打暴力吧 本題很考驗 能力,難度不大,主要是細節繁多。我調了1h 樹鏈剖分的原理不再贅述 詳見 資訊學奧賽一本通 提高版 主要說一下一些容易錯的細節。1 include 2 include 3 include 4 typed...
洛谷 P3372 線段樹 1
今天植樹節,來種一棵線段樹。傳送門如題,已知乙個數列,你需要進行下面兩種操作 1.將某區間每乙個數加上x 2.求出某區間每乙個數的和 輸入格式 第一行包含兩個整數n m,分別表示該數列數字的個數和操作的總個數。第二行包含n個用空格分隔的整數,其中第 i 個數字表示數列第 i 項的初始值。接下來m行每...
線段樹1 洛谷P3372
如題,已知乙個數列,你需要進行下面兩種操作 1.將某區間每乙個數加上x 2.求出某區間每乙個數的和 輸入格式 第一行包含兩個整數n m,分別表示該數列數字的個數和操作的總個數。第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。接下來m行每行包含3或4個整數,表示乙個操作,具體如下...