P2468 SDOI2010 粟粟的書架 題解

2022-05-05 15:00:12 字數 2843 閱讀 1699

你有乙個長r,寬c的矩陣,矩陣上每個格仔有權值,有m次詢問,每次給出乙個矩形左上角\(x1,y1\)和右下角\(x2 ,y2\),以及乙個值h,求:在該矩形覆蓋的權值和是否大於h,最小需要幾個權值就可以大於h。

【資料規模和約定】

對於10%的資料,滿足r, c≤10;

對於20%的資料,滿足r, c≤40;

對於50%的資料,滿足r, c≤200,m≤200,000;

另有50%的資料,滿足r=1,c≤500,000,m≤20,000;

對於100%的資料,滿足1≤pi,j≤1,000,1≤hi≤2,000,000,000。

很顯然,這道題目是讓我們用兩種方式去做,也就是:這題是二合一的題目,考慮前50%:

\(r,c\)很小,所以:該矩形很小,我們思考:如何去統計答案?由於要求最少數目,所以會想到二分答案,但是二分答案什麼值呢?

考慮後50%,一條鏈的情況,那麼肯定會想到是資料結構,那麼用什麼資料結構可以輕易從大到小取數且不超時呢?

具體:我們二分取的數的個數,然後在該區間從大到小取(保證了選的數目最小),那麼我們又會發現:這根本不需要二分,只需要暴力地排序就可以了,很顯然,你絕對會t到飛起。那麼就必須找一些很神奇的做法。

在啟發之下,我也明白了下面這個很巧妙的方法。

由於權值\(p\in[1,1000]\),我們的k的含義就是:小於等於p的值。

那麼我們如何用k去統計我們最後的答案呢?

首先明白一件事:我們要做的是從大到小取數,使和大於等於h,那麼,k的真正含義就是:我們取的一系列數的下界

所以我們可以用二維字首和來維護資訊:用\(sum_\)表示從\((1,1)\)到\((i,j)\)小於等於k的數的和,\(num_\)表示,小於等於k的數的個數。那麼很顯然,我們去二分這個k,找到最大的可以恰好滿足的,(恰好滿足表示:當前這個數,+1就無法滿足,-1也可以滿足)但是請注意顯然,我們當前這個k的val可能回比要求的h大很多,所以我們需要用\(num_\)減去不需要的個數.

void main1() 

int x1,x2,y1,y2,h;

while(m--)

//這裡就是上文說的:減去多餘的

printf("%d\n",number(x1,y1,x2,y2,ans)-(value(x1,y1,x2,y2,ans)-h)/ans);

//考慮為什麼可以這樣寫:我們二分出來的數,一定是和大於等於h中最大且可以取到的數,所以多出來的值一定就是當前這個數,那麼我們只需要做差,然後除這個數下取整就可以完美解決。

} }return;

}

考慮我們本題的後50%:

一條鏈,取區間,查詢和,而且:每個點的值非常小,最大為1000,那麼顯然我們可以想到乙個暴力的做法:

每次都把區間扔到優先佇列裡,從大到小,從頭到尾,取數。很顯然t到飛起,那麼我們就需要乙個更加優秀的資料結構。經分析當然是主席樹更合適(當然,splay完全可以寫。實在懶得打**。。。。。。)

首先,我們,每個葉子節點儲存:

1.值為當前點的數的個數(size)

2.這個數的和(sum)

而非葉子節點要記錄:

1.左右兒子的下標(注意:主席樹為了節省空間,並不是像線段樹那麼直接儲存,而是類似動態開點的思想)

2.它的左右邊界內數的個數。(size)

3.左右邊界內數的和。(sum)

顯然:我們的葉子節點從小到大,可以滿足從大到小選的性質。

具體解決:

int dfncnt;

inline int build(int l,int r)

return rt;

}inline int query(int u,int v,int l,int r,int h)t[20000005];

int r,c,m;

long long a2[500005];

long long b[500005];

long long a1[205][205];

long long sum[205][205][1005];

int tot[205][205][1005];

inline long long value(int x1,int y1,int x2,int y2,int val)

inline int number(int x1,int y1,int x2,int y2,int val)

void main1()

int x1,x2,y1,y2,h;

while(m--)

printf("%d\n",number(x1,y1,x2,y2,ans)-(value(x1,y1,x2,y2,ans)-h)/ans);

} }return;

}int dfncnt;

//建樹,注意:建樹建的是空樹

inline int build(int l,int r)

return rt;

}//查詢,可以理解為二分思想

inline int query(int u,int v,int l,int r,int h)

ans+=(h+b[l]-1)/b[l];

//用左子樹來補

//注意!!!我用了離散化,所以這裡我用的是b[l],如果不離散化,直接用l就可以了

return ans;

}//歷史版本的根的編號

int his[10000005];

void main2()

while(m--)

int ans=query(his[y1-1],his[y2],1,n1,h);

cout<} return;

}int main()

P2468 SDOI2010 粟粟的書架

幸福幼兒園b29班的粟粟是乙個聰明機靈 乖巧可愛的小朋友,她的愛好是畫畫和讀書,尤其喜歡thomas h.cormen的文章。粟粟家中有乙個r行c列的巨型書架,書架的每乙個位置都擺有一本書,上數第i行 左數第j列擺放的書有pi,j頁厚。粟粟每天除了讀書之外,還有一件必不可少的工作就是摘蘋果,她每天必...

P2468 SDOI2010 粟粟的書架

傳送門 二合一題.前面 50 分 考慮取書顯然優先取厚的,所以答案滿足單調性 發現 p 不大,所以考慮二分最小厚度 mid 把大於等於 mid 的書取走 維護 cnt i j k 表示位置 i,j 為右下角一直到 1,1 的矩形內厚度大於等於 k 的書的數量 維護 sum i j k 表示位置 i,...

Sdoi2010 粟粟的書架

主席樹 二分 字首和 time limit 30 sec memory limit 552 mb submit 919 solved 366 submit status discuss 第一行是三個正整數r,c,m。接下來是乙個r行c列的矩陣,從上到下 從左向右依次給出了每本書的頁數pi,j。接下來...