題目出處:codeforces-375d
【題面】:
有乙個大小為n且以1為根的樹,樹上每個點都有對應的顏色ci。現給出m次詢問v, k,問以v為根的子樹中有多少種顏色至少出現了k次。
【輸入格式】
第一行兩個數n,m表示樹的大小以及詢問的次數。
第二行n個數表示樹上每個結點的顏色。
接下來的n-1行,每行兩個數a, b表示樹上的邊。
接下來m行,每行兩個數v, k表示詢問。
【輸出格式】
m行,每行乙個數表示第i次詢問的答案。
樣例輸入1
8 51 2 2 3 3 2 3 3
1 21 5
2 32 4
5 65 7
5 81 2
1 31 4
2 35 3
樣例輸出122
101樣例輸入2
4 11 2 3 4
1 22 3
3 41 1
樣例輸出2
4資料範圍
2≤n≤100000
1≤m≤100000
1≤ci≤100000
1≤a, b≤n, a≠b
1≤v≤n, 1≤k≤100000
對於其中30%的資料保證n,m≤100且ci≤n
對於其中60%的資料保證n≤5000
【考試歷程】:立馬想到暴力演算法,設f[i][j]表示以i為根結點的子樹中顏色為j的節點數量,然後樹形dp由兒子傳給爸爸就可以得到每乙個點子樹顏色資訊,最後對於每乙個詢問暴力查詢即可.
時間複雜度o(n2m*n)=o(n3m),陣列只能開到5000 * 5000,然後就只能得到60分。
隨後想到子樹查詢便想到了dfs序轉換為區間問題,然後我想到了莫隊貌似可做,然後就敲了一下。
emmmmm,zz的我不懂得變通,原來的莫隊題目k是定製,這次是變了的,然後我還在用老方法,寫到一半感覺又寫不下去了,然後直接重敲,瞎搞一通,只拿了30分…
【正解】:相信自己,正解就是莫隊(或者分塊,至於什麼用啟發式合併做的大佬emmm),其實對於每乙個詢問k,我們只需維護乙個樹狀陣列,下標表示顏色數量,值代表有多少顏色達到了k個,動態去維護一下即可。
code
#include
using
namespace std;
struct fuk
a[200011];
struct fuc
q[100011];
int top=
0,cnt=
0,first[
100011
],n,m,blo;
int dfn[
100011
],pos[
100011
],size[
100011
],to[
100011];
int c[
100011
],b[
100011
],v[
100011
],t[
100011
],s,ans[
100011];
void
add(
int x,
int to)
void
dfs(
int x,
int fa)
}bool
mycmp
(fuc a,fuc b)
void
change
(int x,
int val)
intask
(int x)
void
insert
(int x)
void
remove
(int x)
intmain()
dfs(1,
0);for
(int i=
1;i<=m;i++
)sort
(q+1
,q+m+
1,mycmp)
;int l=
0,r=0;
for(
int i=
1;i<=n;i++
) b[i]
=v[pos[i]];
for(
int i=
1;i<=m;i++
)for
(int i=
1;i<=m;i++
)printf
("%d\n"
,ans[i]);
}
這裡提醒一下大家如果要用樹狀陣列,一定要注意下標和0。然後其實如果你用以上的**將莫隊while操作的第一項和第二項互換,你會發現tle了。
為什麼?假設我們將詢問排序後第乙個問題區間為[3,3],你的l為1,然後先執行remove操作導致原本就為0的to[b[i]]又-1,其實本來我們應該先把這乙個節點加入考慮區間中先+1即r的增加導致目前區間變為[1,3]後再由l的增加來減除[1,2]區間帶來的影響;不然直接這樣下標就又變成-1,樹狀陣列直接gg了,一定要注意
呵呵我不會說有更快的方法的【誰叫我一開始想到了樹狀陣列】
code
#include
using
namespace std;
struct fuk
a[200011];
struct fuc
q[100011];
int top=
0,cnt=
0,first[
100011
],n,m,blo;
int dfn[
100011
],pos[
100011
],size[
100011
],to[
100011];
int c[
100011
],b[
100011
],v[
100011
],t[
100011
],s,ans[
100011
],sum[
100011];
void
add(
int x,
int to)
void
dfs(
int x,
int fa)
}bool
mycmp
(fuc a,fuc b)
void
insert
(int x)
void
remove
(int x)
intmain()
dfs(1,
0);for
(int i=
1;i<=m;i++
)sort
(q+1
,q+m+
1,mycmp)
;int l=
0,r=0;
for(
int i=
1;i<=n;i++
) b[i]
=v[pos[i]];
for(
int i=
1;i<=m;i++
)for
(int i=
1;i<=m;i++
)printf
("%d\n"
,ans[i]);
}
sum陣列下標和上面的樹狀陣列含義相同,表示顏色數為k的顏色種類。
這裡的sum陣列運用的就很巧妙,因為乙個顏色的數量假設由k1增加到k2,那麼很明顯數量為k1—k2的所有顏色數量都會+1,而乙個顏色的減少只會讓原先的顏色數表示的sum-1,那麼對於每乙個詢問區間我們考慮完了所有的顏色,那麼sum[k]就是我們的答案【因為乙個顏色在該區間的數量》=k,必定都會使sum[k]這個陣列+1】,這就是巧妙之處。
總結:要提公升思想的深度,不侷限於做過的題目,懂得舉一反三是很重要的,要加深對演算法的理解,靈活運用,要多刷題多思考。
bzoj3956 Count 解題報告
題目大意 給出n 個數,定義一種好點對 i j 令i需要滿足如下兩個條件之一 1.i j 1 2.對於 k i,j 均有a k n a i a j 詢問若干個區間中的好點對個數。題解 我們首先可以發現,這樣的好點對是不相交的 但會出現包含情況 既不可能出現兩個好點對 i 1,j1 i 2,j2 使得...
count 列名 與count 說明
1 count 會統計值為null的行,而count 列名 不會統計此列為null值的行 2 不要使用count 列名 或者count 常量 來代替count count 就是sql92定義的標準統計行數的語法,跟資料庫無關,跟null和非null無關 3 count 列 對應的列欄位如果建了索引,...
MySQL學習筆記 count的查詢
count 計算乙個表的行數 select count from t在事務支援,併發能力,資料安全上innodb引擎表現都較myisam表現優良 innodb是索引組織表 主鍵索引樹的葉子節點是資料 普通索引樹的葉子節點是主鍵值 普通索引樹主鍵索引樹小很多 對於count 的操作,遍歷哪個索引樹得到...