輸入n(1
e5
)n(1e5)
n(1e5)
表示一棵根為1的樹有n
nn個節點
接下來n−1
n-1n−
1行每行u,v
u,vu,
v表示樹邊
接下來一行n
nn個數,c1,
c2,…
,cn(
1≤ci
≤n
)c_1,c_2,\dots,c_n(1\leq c_i\leq n)
c1,c2
,…,
cn(
1≤ci
≤n)
表示節點顏色
接下來m(m
≤n
)m(m\leq n)
m(m≤n)
個詢問,每個詢問詢問一顆子樹有多少個顏色。
用樹上啟發式合併(dsu)
先重鏈剖分出重兒子。操作
做法很暴力,但是複雜度就是n
log(n
)n\log(n)
nlog(n
)。
#include
using
namespace std;
const
int n=
1e5+9;
int c[n]
,ans[n]
;struct edgee[n<<1]
;int head[n]
,cnt;
int n;
inline
void
add(
int u,
int v)
; head[u]
=cnt++;}
int son[n]
,siz[n]
;void
dfs(
int u,
int fa)
}int he[n]
,nowson,sum;
void
calc
(int u,
int fa,
int val)
}void
dsu(
int u,
int fa,
bool kep)
if(son[u]
)dsu
(son[u]
,u,1
),nowson=son[u]
;calc
(u,fa,1)
;nowson=0;
ans[u]
=sum;if(
!kep)
}int
main()
for(
int i=
1;i<=n;i++
)cin>>c[i]
;dfs(1
,0);
dsu(1,
0,1)
;int m;
cin>>m;
while
(m--
)return0;
}
U41492 數顏色 樹上啟發式合併
樹上啟發式合併的經典問題。首先離線處理答案。用乙個顏色陣列記錄某種顏色是否存在過,然後由於不同子樹統計答案的時候互不影響,我們枚舉子樹的時候要清空之前的陣列,但是這就帶來了乙個問題,我們無法向上合併答案了。啟發式合併的做法是我們先考慮樹剖預處理,然後對於統計乙個結點的答案,先暴力遞迴所有輕兒子的答案...
CSP S 2019 樹上的數(樹上推理)
過了這麼久看看自己要多久才能切這題,發現還是想歪了一次。先考慮暴力的做法。還是貪心的逐位確定,逐位確定判有沒有解,相當於下面的問題 樹上有一些路徑,一條路徑表示要把 x 的數字換到 y 去,問有沒有解。對於一條路徑 p 1 p 2 p m 限制如下 1.p 1 p 2 是 p 1 的所有相鄰邊中時間...
CSP2019 樹上的數
給定乙個大小為 n 的樹,它共有 n 個結點與 n 1 條邊,結點從 1 sim n 編號。初始時每個結點上都有乙個 1 sim n 的數字,且每個 1 sim n 的數字都只在恰好乙個結點上出現。接下來你需要進行恰好 n 1 次刪邊操作,每次操作你需要選一條未被刪去的邊,此時這條邊所連線的兩個結點...