題意:給定一棵 \(n(2\leq n\leq 10^5)\) 個結點的樹,根結點為 \(1\) 號結點,每個結點有顏色 \(c(\leq c\leq 10^5)\) 。然後 \(m(1\leq m\leq 10^5)\) 次詢問,每次詢問給兩個引數 \((v,k)\) ,詢問 \(v\) 子樹內,頻次至少有 \(k\) 次的顏色有多少種。
題解:經典計數顏色的數量,使用莫隊演算法。不過這一次顏色的數量 \(k\) 不確定,也要作為乙個維度進行轉移。這一次查詢的並非樹鏈而是子樹,所以結點出棧的時候不需要刪除這個結點的資訊。對每個詢問給乙個區間 \([fst[v],lst[v]]\) 查詢頻次至少有 \(k\) 次的顏色有多少種。考慮帶修改的莫隊演算法,塊的大小為 \(\sqrt[3]\) ,總複雜度為 \(o(\sqrt[3])\) 。但是實測表明開 \(\sqrt[2]\) 更快,不知道原因是什麼,可能和這裡的區間並非任意指定有關(是dfs序的區間)。
namespace moalgorithmontree
}struct node
} node[maxm];
ll ans[maxm];
int l, r, k;
ll curans;
int c[maxn], cnt[maxc], sum[maxn];
void add(int x)
void sub(int x)
void addk()
void subk()
void solve()
idt = 0;
dfs(1, 0);
block = (int)ceil(pow(n, 0.667));
for (int i = 1; i <= m; ++i)
sort(node + 1, node + 1 + m);
l = 1, r = 0, k = 0, curans = n, sum[0] = n;
for (int i = 1; i <= m; ++i)
for (int i = 1; i <= m; ++i)
printf("%lld\n", ans[i]);
}};
但是換一種思路,其實k沒有必要作為其中乙個維度,不過就不再維護curans,或者說,curans是乙個陣列,curans[i]表示頻次大於等於i的顏色數。考慮一種顏色頻次從cnt增加到cnt+1時,只會讓大於等於cnt+1的答案+1,對於大於等於cnt其實是沒有變化的。
這道題也可以樹上啟發式合併做。
樹上莫隊演算法
繼續回來寫部落格 記錄點有意思的題目什麼的。貌似寫過這個的沒多少人 所以我也記錄一點。首先序列上的莫隊大家都應該很熟悉了 那麼樹上的莫隊要怎麼搞呢?先來看個題目 spoj cot2 求樹上兩點間路徑上有多少個不同的點權。序列上的莫隊是把詢問按照左端點分塊了 可是樹上沒有左端點,怎麼辦呢?我們把樹分塊...
樹上莫隊演算法
樹上莫隊,顧名思義就是把莫隊搬到樹上。我們從一道題目入手 sdoi2018 原題識別 spoj count on a tree ii 題目意思很明確 給定乙個 n 個節點的樹,每個節點表示乙個整數,問 u 到 v 的路徑上有多少個不同的整數。像這種不帶修改數顏色的題首先想到的肯定是樹套樹莫隊,那麼如...
樹上莫隊演算法
樹上莫隊,顧名思義就是把莫隊搬到樹上。我們從一道題目入手 sdoi2018 原題識別 spoj count on a tree ii 題目意思很明確 給定乙個 n 個節點的樹,每個節點表示乙個整數,問 u 到 v 的路徑上有多少個不同的整數。像這種不帶修改數顏色的題首先想到的肯定是樹套樹莫隊,那麼如...