傳送門:https://www.luogu.org/problemnew/show/P4332
題目大意:給定一棵樹,每個點有3個輸入信號的接口(連向外部或兒子)和1個輸出信號的接口(連向父親),1號點是根。信號是0或1。一個點輸出的信號是輸入信號中較多的那個。每次修改一個外部接口傳入的信號,輸出1號節點輸出的信息。
看到網上很多log^2甚至log^3的做法,這裏放一個lct的一個log做法,可能是我的原創做法吧畢竟網上目前似乎沒有找到類似思路的題解。
其實這題我的第一感覺是動態dp……說實話這確實像個動態dp模型,我們也可以用類似動態dp的做法來做。
首先,當一個點接收到>=2個1時,輸出1,否則輸出0。
我們可以在lct中維護一個si,表示它的虛兒子有多少個1傳上來。
再維護一個b(i,0/1),表示:i所在的這條重鏈,如果從鏈底額外輸入一個0/1,從鏈頂輸出的會是什麼值。
這是我的做法最大的特點:並非直接維護每個點具體會輸出什麼,而是維護一整段鏈的信息。(這裏是不是很像動態dp?)
爲什麼要記一個0/1呢?爲了方便合併重鏈的信息,只要考慮一個0/1的信息從右側傳進來,傳到中點時會變成什麼,再傳到左側去就行了。
access時只需要用當前點的b(i,0)值修改父親的s值,修改和查詢也都很好操作。
我們會發現這棵lct甚至不需要makeroot,所以無論是代碼難度還是運行速度都完爆樹剖!
#include<bits/stdc++.h>
using namespace std;
#define gc getchar()
#define pc putchar
#define li long long
inline int read(){
int x = 0,c = gc;
while(!isdigit(c)) c = gc;
while(isdigit(c)) x = (x << 1) + (x << 3) + (c ^ '0'),c = gc;
return x;
}
inline void print(int q){
if(q >= 10) print(q / 10);
pc(q % 10 + '0');
}
int n,m,f[2000010],fsts[2000010],nxt[2000010],l[2000010],r[2000010],s[2000010];
bool a[2000010],b[2000010][2];
void dfs(int q){
for(int i = fsts[q];i;i = nxt[i]){
if(i <= n) dfs(i);
s[q] += a[i];
}
a[q] = b[q][0] = (s[q] >= 2);
b[q][1] = (s[q] >= 1);
}
inline bool is(int q){
return l[f[q]] != q && r[f[q]] != q;
}
inline void ud(int q){
b[q][0] = (s[q] >= 2);
b[q][1] = (s[q] >= 1);
if(r[q]){
if(b[r[q]][0]) b[q][0] = b[q][1];
else if(!b[r[q]][1]) b[q][1] = b[q][0];
}
if(l[q]){
if(b[q][0]) b[q][0] = b[q][1] = b[l[q]][1];
else if(!b[q][1]) b[q][0] = b[q][1] = b[l[q]][0];
else b[q][0] = b[l[q]][0],b[q][1] = b[l[q]][1];
}
}
inline void ro(int q){
int p = f[q];
if(l[f[p]] == p) l[f[p]] = q;
else if(r[f[p]] == p) r[f[p]] = q;
f[q] = f[p];f[p] = q;
if(l[p] == q){
l[p] = r[q];r[q] = p;
if(l[p]) f[l[p]] = p;
}
else{
r[p] = l[q];l[q] = p;
if(r[p]) f[r[p]] = p;
}
b[q][0] = b[p][0];b[q][1] = b[p][1];ud(p);
}
inline void sp(int q){
while(!is(q)){
int p = f[q];
if(!is(p)){
if((l[f[p]] == p) ^ (l[p] == q)) ro(q);
else ro(p);
}
ro(q);
}
}
inline void ac(int q){
int p = 0;
while(q){
sp(q);
s[q] += b[r[q]][0];
r[q] = p;
s[q] -= b[p][0];
ud(q);
p = q;q = f[q];
}
}
int main(){
int i,u;
n = read();
for(i = 1;i <= n;++i){
u = read();f[u] = i;nxt[u] = fsts[i];fsts[i] = u;
u = read();f[u] = i;nxt[u] = fsts[i];fsts[i] = u;
u = read();f[u] = i;nxt[u] = fsts[i];fsts[i] = u;
}
for(i = n + 1;i <= 3 * n + 1;++i) a[i] = read();
dfs(1);
m = read();
for(i = 1;i <= m;++i){
u = read();
ac(f[u]);sp(f[u]);
a[u] ^= 1;a[u] ? ++s[f[u]] : --s[f[u]];
ud(u);
ac(1);sp(1);print(b[1][0]);pc('\n');
}
return 0;
}
目前在luogu上2411ms是rk1。