題目描述
一棵n個點的樹,每個點的初始權值為1。對於這棵樹有q個操作,每個操作為以下四種操作之一:
+ u v c:將u到v的路徑上的點的權值都加上自然數c;
- u1 v1 u2 v2:將樹中原有的邊(u1,v1)刪除,加入一條新邊(u2,v2),保證操作完之後仍然是一棵樹;
* u v c:將u到v的路徑上的點的權值都乘上自然數c;
/ u v:詢問u到v的路徑上的點的權值和,求出答案對於51061的餘數。
輸入輸出格式
輸入格式:
第一行兩個整數n,q
接下來n-1行每行兩個正整數u,v,描述這棵樹
接下來q行,每行描述乙個操作
輸出格式:
對於每個/對應的答案輸出一行
輸入輸出樣例
輸入樣例#1:
3 21 2
2 3
輸出樣例#1:
說明10%的資料保證,1<=n,q<=2000
另外15%的資料保證,1<=n,q<=5*10^4,沒有-操作,並且初始樹為一條鏈
另外35%的資料保證,1<=n,q<=5*10^4,沒有-操作
100%的資料保證,1<=n,q<=105,0<=c<=104
題解差不多算是lct
\mathcal
lct比較常規的操作了吧。。。沒有思維難度啊。。。
標記下傳什麼的模擬線段樹就好了,貌似要開uns
igne
dint
\mathcal
unsign
edin
t,因為那個猥瑣的模數的平方剛好大於int
\mathcal
int:
51061
×51061
=2607225721
>231
=2147483648
51061\times51061=2607225721>2^=2147483648
51061×
5106
1=26
0722
5721
>23
1=21
4748
3648
**
#include
#define ls son[v][0]
#define rs son[v][1]
#define x(a) a=(a*s)%mod
#define j(a) a=(a+s)%mod
#define uint unsigned int
using
namespace std;
const uint m=
1e5+
5,mod=
51061
;uint n,q,dad[m]
,son[m][2
],sta[m]
,add[m]
,mul[m]
,sum[m]
,siz[m]
,val[m]
;bool rev[m]
;bool
notroot
(int v)
voidup(
int v)
void
turn
(int v)
void
padd
(int v,
int s)
void
pmul
(int v,
int s)
void
push
(int v)
}void
spin
(int v)
void
splay
(int v)
}void
access
(int v)
void
beroot
(int v)
void
split
(int x,
int y)
void
link
(int x,
int y)
void
cut(
int x,
int y)
voidad(
int a,
int b,
int val)
voidmu(
int a,
int b,
int val)
voidin(
)voidac(
)}}int
main()
P1501 國家集訓隊 Tree II
傳送門 顯然 lct 維護,除了翻轉標記,還要維護加法,乘法和子樹大小 注意模數看起來很小,但是乘的時候還是會爆 int 所以要用 unsigned int 中的標記為延時標記,就是當前節點的標記說明當前節點還沒更新,要等到下傳標記時才更新,個人認為會好寫一些 不用考慮先乘還是先加 注意乘法標記初始...
P1501 國家集訓隊 Tree II
p1501 國家集訓隊 tree ii 樹上懶惰標記維護動態路徑模板題 其實做這題也能練一下對 lct 的了解 我們對 x,y 這條路徑修改時 split x,y y 傳到 y 上去就行了 我們發現不管什麼操作都會用到 access 其中把底下的點上旋 splay 的同時會把 y 上的標記取下來 和...
P1501 國家集訓隊 Tree II
一棵n個點的樹,每個點的初始權值為1。對於這棵樹有q個操作,每個操作為以下四種操作之一 第一行兩個整數n,q 接下來n 1行每行兩個正整數u,v,描述這棵樹 接下來q行,每行描述乙個操作 對於每個 對應的答案輸出一行 3 2 1 22 3 1 3 4 1 1410 的資料保證,1 leq n,q l...