發表文章

目前顯示的是有「持久化」標籤的文章

[POJ] 2104. K-th Number

題目連結: http://poj.org/problem?id=2104 裸的區間第K大值,曾經會過可是又忘記了,只記得關鍵字持久化,被雷了才知道。原來就是原本的序列第K大是直接用樹上的節點作二分搜,但是區間的話就變成要用$[L,R]$的和做節點二分搜,而要算$[L,R]$的和,其實就用持久化線段樹把$roots[R]-roots[L]$即可。 #include <iostream> #include <vector> #include <algorithm> #include <cassert> using namespace std; #define PB push_back #define ALL(x) (x).begin(), (x).end() const int N = 100000 + 5; const int MEM = 2000000; class LiSan{ private: vector<int> v; public: inline void init(){v.clear();} inline void insert(int x){v.PB(x);} inline int size(){return v.size();} inline void done(){ sort(ALL(v)); v.resize(distance(v.begin(), unique(ALL(v)))); } inline int get(int x){ return distance(v.begin(), lower_bound(ALL(v), x)); } inline int inv_get(int x){return v[x];} } lisan; ...

[SPOJ] DQUERY - D-query (持久化)

圖片
題目連結: http://www.spoj.com/problems/DQUERY/ 被雷了才會做QQ,本題有兩種做法,一種是持久化線段樹,作法滿特別的(?,序列要將在每個時間點最遠的各個數字改成一,其他改成零(如圖) 那詢問一個$[l, r]$時,就只要對第$r$時間點的線段樹詢問$[l, r]$即可。 #include <bits/stdc++.h> using namespace std; #define PB push_back #define ALL(x) (x).begin(), (x).end() const int N = 30000 + 5; const int MEM = 900000; class LiSan{ private: vector<int> v; public: inline void init(){v.clear();} inline void insert(int x){v.PB(x);} inline int size(){return v.size();} inline void done(){ sort(ALL(v)); v.resize(distance(v.begin(), unique(ALL(v)))); } inline int get(int x){ return distance(v.begin(), lower_bound(ALL(v), x)); } } lisan; class SegTree{ private: struct Node{ int val, lc, rc; Node(){val=0;lc=-1;rc=-1;} };...

[TIOJ] 1271. [IOI 2012] Scrivener 斯克里夫尼

題目連結: http://tioj.infor.org/problems/1271 應該很明顯可以用持久化資料結構做掉,如果知道有rope這東東的話可以直接拿來用,這題就被秒掉了。不過我們還是該秉持個手寫資料結構,所以我就寫了個持久化treap,而因為我每次插入的時候都保證key是遞增的,所以可以不用寫split把它拆掉再合起來,算是一個小常數優化(?,不過注意一下因為treap並不是保證logN的,所以有可能有幾條太長的路徑,導致MLE掉,這裡可能要多試幾次,或者直接用個7122這神秘數字避免(? #include "lib1271.h" #include <random> #include <ctime> #include <algorithm> #define copyNode(a,b) a->l=b->l;\ a->r=b->r;\ a->val=b->val;\ a->pri=b->pri;\ a->key=b->key; #define N 1000000 std::minstd_rand rd(7122); struct Treap{ int key; unsigned short pri; char val; Treap *l, *r; Treap(){} Treap(char c,int k){ pri=rd(); key=k; val=c; l=r=nullptr; } }; int sizes[N+1]={0}; Treap* treaps[N+1]={nullptr}; int opt=0; Treap...

[TIOJ] 1827. Yet another simple task ^____^

題目連結: http://tioj.infor.org/problems/1827 不難發現本題可以對答案二分搜,因為S有單調性,那驗證的時候就是要驗證一個區域是不是有至少k個數小於S,我原本想說用個BIT套treap之類的,但估完複雜度後發現會TLE,實在苦思不知該如何做,直到有人雷了我說誰區間和在用BIT的,我才發現可以用維護前綴和的精神做這題,也就是說每個前綴變成存一棵treap,但是如果每一個前綴都重新插一遍所有東東到treap裡面會發現預處理變成$O(n^2 log(n))$,明顯會TLE,所以不妨用持久化的概念,也就是讓一部分是共用的,有修改到的部分再複製出來就好了,因為複製時最多只會動到一條跟到葉的路徑也就是最多$log(n)$個節點,因此複雜度還是$log(n)$,只是記憶體有點龐大而已。 #include <bits/stdc++.h> using namespace std; #define N 100000 struct treap{ treap *l, *r; int pri,val,size; treap(){l=r=nullptr;size=0;} treap(int x){l=r=nullptr;pri=rand();val=x;size=1;} }; inline int gSize(treap* x){return x?x->size:0;} inline void pull(treap* x){x->size=gSize(x->l)+1+gSize(x->r);} int arr[N+5], n; treap* root[N+5]; bool isOK(int,int,int); void split(treap*,int,treap*&,treap*&); treap* merge(treap*, treap*); int query(treap*,int); int main(){ ios_base::sync_with_stdio(0);cin.tie(0);...