啊剛學這個啊
剛過了一道題就屁顛屁顛來寫部落格很虛啊
bzoj4553
就是這道題
說一下我對cdq分治的理解
我感覺。。這個就類似於。。把暴力,轉化為。。容易優化的暴力。。然後優化??
並且一般只用於處理問題具有單調性的題,即f[i]對任意f[j](j=,不產生影響。
例如最長上公升子串行的問題
我們本來需要列舉這個j,但是通過cdq分治就不需要去全部列舉了
我們處理1~n的時候,如果1~n/2已經全部處理完畢,那麼就可以用1~n/2的結果去更新n/2+1~n的結果
注意 這裡是更新,而不是算出
因為等會兒我們會列舉n/2+1~n/2+n/4去更新n/2+n/4+1~n
這樣,f[i]就會被所有比他小的點更新
這裡仍然舉最長上公升子串行的例子,暴力dp顯然是n^2,然而上面說的這個想法,如果不加任何處理。。也是n^2,甚至常數更大
但是我們可以對前面的值進行一些處理,比如按照a[i]排序。
同時對後面的值處理,那麼我們就可以線性推,把一次更新的時間優化到2(r-l),整個時間效率也就優化到了n*log n
那麼再來看看看看一開始說的那道題,其實我們只要
a[i]正確性顯然
那麼考慮cdq分治
這次有二維的條件,顯然乙個排序後仍然不能確保前面的值全部可以取,那麼怎麼辦呢
排序後顯然只有一維的條件了,我們再套乙個cdq我們可以用樹狀陣列,記錄權值的字首和就可以了
自己也不太懂啊就這樣吧
code:
#include#include
#include
#include
#include
#include
#include
#include
#include
#define inf 1e9
#define ll long long
#define for(i,j,k) for(ll i=j;i<=k;i++)
#define dow(i,j,k) for(ll i=k;i>=j;i--)
using
namespace
std;
int n,m,a[100001],f[100001],ff[100001],mi[100001],mx[100001],num[100001];
inline
bool cmp1(int x,int y)
void add(int x,int v)
int get(int x)
void solve (int l,int r)
int mid=(l+r)>>1;
solve(l,mid);
for(i,l,r) num[i]=i;
sort(num+l,num+mid+1,cmp2);sort(num+mid+1,num+r+1,cmp1);
int poi=l;
for(i,mid+1,r)
for(i,l,poi) add(mx[num[i]],0);
solve(mid+1,r);
}int main()
solve(1,n);
int ans=0;
for(i,1,n) ans=max(ans,f[i]);
printf("%d\n",ans);
}
CDQ分治概述
log l og 的時間把它變成離線問題。正好有些題目的離線問題是比較簡單的。具體是什麼意思呢?我們對於每一層分治,只考慮前一半對於後一半的影響,然後在每個詢問當中記錄下來影響。最後把所有影響合併就可以得到每乙個詢問的答案。舉個例子 區間修改區間查詢。首先,在時間軸上離線分治。每一層分治後把詢問和查...
CDQ分治總結
cdq這個東西嘛,說容易其實也很容易,說難其實也有些難,但只要細細品味,定能發現其中的真理的!那真理,也會像蝴蝶一般,破蛹而出,化身為一道亮麗的風景線。題記。咳咳,閒話就講到這裡了,切入正題。首先我們來了解一下cdq分治這個東東。cdq分治,他的常數小,但必須離線操作the most importa...
cdq分治小結
一般的分治,眾所周知的,是通過將大的問題拆小,然後對小問題的答案進行合併得到大問題的答案,但是cdq分治不是。我們知道,分治時,將乙個區間從中間斬開,分兩半處理,cdq分治在處理完之後,不是合併答案,而是計算左區間對右區間的貢獻,這樣子可以將維度降低,問題就更好做了。現在有 n nn 個二元組,每個...