Count 學習報告

2021-09-25 10:02:24 字數 4150 閱讀 9384

題目出處: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 的操作,遍歷哪個索引樹得到...