有n個多公尺諾骨牌,從左到右排列,每乙個骨牌都有乙個高度li,向右推倒,它會直接向右倒下,如下圖,倒下後該骨牌的頂端落在xi+li的位置,(xi是它位於的座標,即倒下時該骨牌不會發生移動)
在倒下過程中,骨牌會碰到其他骨牌,碰到的骨牌會向右倒,如下圖,最左邊的骨牌倒下會碰倒a,b,c,a,b,c會倒下,但是不會直接碰到d,但是d會因為c的倒下而碰倒。
現在給你n個骨牌的座標xi,和每個骨牌的高度li。則乙個骨牌能碰倒另乙個骨牌當切僅當xi+li≥xj。同時有q個詢問 [l,r],問向右推到第l個骨牌,最少需要多少代價讓r倒下。你可以臨時增加某個骨牌的高度,增加1個高度的代價是1.
第一行是乙個整數n,表示共n個骨牌
接下來n行描述每個骨牌的資訊xi,li表示每個骨牌的位置與高度,保證xi接下來一行是乙個整數q,表示q個詢問
接下來是q行,表示每個詢問l,r,保證1<=l對於每個詢問,分q行列印答案
61 5
3 34 4
9 210 1
12 1
41 2
2 42 5
2 6011
220%資料:n,q<=1000,xi<=10000
40%資料:n,q<=10000,xi<=100000
100%資料:2<=n<=100000,1<=q<=200000,xi<=10^9
這道題暴力是很容易拿到40分的(因為資料水了)
但蒟蒻竟然連題目意思都搞錯了,最後抱了個0鴨蛋回家
「問向右推到第l個骨牌,最少需要多少代價讓r倒下。」 若按我的理解就是從1開始推到l,然後問還需要多少代價會使r倒下
但實際上是只把l推倒,所以個人意見把題改為「問向右推倒第l個骨牌,最少需要多少代價讓r倒下。」更清楚些
由於資料範圍較大,特別是詢問有200000次,如果每次都現求的話,肯定不現實,所以我們肯定需要什麼東西進行預處理,然後o(1)查詢
我們可以把題目轉化為 求某乙個區間內沒有被覆蓋到的長度是多少 然後用字尾和進行處理
首先定義 sum [ i ] 表示第 i 個骨牌到最後乙個骨牌之間,不能被覆蓋到的長度
然後可以利用並查集的思想,把中間沒有斷點(也就是說前乙個骨牌倒下可以推倒這乙個)的骨牌看作是乙個整體,保留這個整體最左邊的點
那麼詢問時,對於第二個骨牌,我們就去尋找他的祖先(他所在整體的最左邊的骨牌),( i 表示第乙個骨牌,j 表示第二個骨牌 ) 然後sum [ i ] - sum [ f i n d (j) ]就是答案了
#include#include#include#include#include#include#include#define n 100009
using namespace std;
int n,q;
struct nodea[n],b[2*n];
int fa[n];
inline int read()
return f*res;
}vectorq[n];
stacks;
long long ans[2*n],sum[n];
int find(int x)
void solve(int x,int id)
int main()
q=read();
for(i=1;i<=q;++i)
for(i=n;i>=1;--i)
if(!s.empty()) sum[i]=sum[s.top()]+a[s.top()].l-a[i].r;//如果中間有斷點,就更新
else sum[i]=0;
s.push(i);//用棧來儲存
int len=q[i].size();
for(j=0;j
} for(i=1;i<=q;++i)
printf("%lld\n",ans[i]);
return 0;
}
CF811E 線段樹 並查集
cf的題面真的是做的美美的,所以就直接扔超連結了 分析 線段樹的葉子結點維護一列的資訊 包括左右端點,有多少聯通塊,以及左右兩列的並查集情況 需要注意的是,這次 中的update返回的是乙個node 第一次 re的原因就是在返回的這個新建的node中 我沒有維護左右端點 在update維護左右兩列的...
並查集防止爆棧
在並查集的時候經常遇到爆棧的情況,這裡給推薦兩種方法預防爆棧 開外掛程式棧 pragma comment linker,stack 1024000000,1024000000 增加乙個陣列用來儲存結點的熵值,使得根節點離子結點平攤下來的距離最小,主要在合併的時候需要用到 if cou fa cou ...
E 食物鏈(帶權並查集)
e 食物鏈 relation有三種取值 假設節點x的父節點為rootx,即p x parent rootx p i relation 0 表示節點x與其父節點rootx的關係是 同 類 p i relation 1 表示節點x與其父節點rootx的關係是 根吃 i p i relation 2 表示...