現在把主席樹的原理給弄清楚了,從i=1開始,每次新插入乙個數,就為他建一棵線段樹(當然第一次i=0的時候是建一棵空樹),線段樹裡面儲存的是1-i的樹的位置情況
簡單來說,如果有m個樹,則每棵線段樹都是範圍為1-m的,至於1-i沒有m個那就先讓它空著不管,我只負責1-i裡面的數的位置情況插入到線段樹裡面,左孩子是大小k<=size/2的,右孩子是k>size的,size是線段樹的深入層次而定,一開始就是m的,而不用每次都為1-i每個樹插入值(不僅耗時,空間也耗不起),我只考慮當前這個ai,至於1到i-1,已經在t[i-1]裡面存了,我如果當前孩子是往左走的,那我復用t[i-1]的右孩子即可,反過來也是一樣的,這樣,每次建樹 最多logn,最多也只建了logn個節點,所有總節點數目為n*logn,在n為不超過千萬的範圍內,是可以承受的。。。不過這道題為什麼要*40才能過。。我也沒搞清,好像覺得不用開這麼大,但我試了下不開久會wa。
因為主席樹每顆線段樹結構相同並且還高度復用,所以他的乙個很奇妙的特性就是他支援加減操作,一般就是用他的減操作,要求區間a到b的,則用t[j] 和t[i-1]的左支相減即可得到當前這個區間裡線段樹左邊存的是多大的,右邊存的是多大的,用pos代進去即可,往左走 往右走,把整個二分走完即可得到答案
樹狀陣列套線段樹我暫時還沒完全弄清,反正為了記錄修改,每次都像之前插入值一樣新開了樹,而且要用離線,把要修改的那些值預先存進去
#include #include #include #include using namespace std;const int n =60000+10;
const int maxn=n*40;
int tot;
int t[n],a[n],t[n],s[n];
int lson[maxn],rson[maxn],c[maxn];
int used[n];
int n,q,m;
struct node
q[10010];
void init()
int build(int l,int r)
int lowbit(int x)
int sum(int x)
return ret;
}int query(int l,int r,int k)
for (int i=r;i;i-=lowbit(i))
while (l>1;
int tmp=sum(r)-sum(l-1)+c[lson[rrt]]-c[lson[lrt]];
if (tmp>=k)
for (int i=r;i;i-=lowbit(i))
lrt=lson[lrt];
rrt=lson[rrt];
}else
for (int i=r;i;i-=lowbit(i))
lrt=rson[lrt];
rrt=rson[rrt];}}
return l;
}int inserts(int rt,int pos,int val)
else
c[newrt]=c[rt]+val;
}return tmp;
}void add(int loc,int p,int val)
}int main()
; }
else;
t[++m]=b;}}
init();
t[0]=build(1,m);
for (int i=1;i<=n;i++)
for (int i=0;i<=n;i++) s[i]=t[0];
for (int i=0;ielse}}
return 0;
}
zoj 2112 主席樹套樹狀陣列 優化
題解思路 如果直接對原來的陣列建立主席樹套樹狀陣列的空間複雜度是 n m log n m log n m 這樣明顯 那麼我們可以對原來的數組建主席樹模型,空間複雜度就是n logn,對m裡面的修改建主席樹套樹狀陣列空間複雜度是m logm logm明顯小了很多。include define lson...
Zoj 2112 線段樹套Treap
樹套樹入門題 樹套樹空間複雜度分析 維護乙個長度為n的序列,線段樹的結點數一般為4n,而treap則是對於每乙個元素 包括重複出現的 都需要乙個空間,那麼第1層的所需要的空間為 1 n 第二層為 2 n 2 所以其實為o h n.那麼所需的空間為o nlog n 但在實際運用中,所形成的線段樹往往不...
ZOJ 2112 線段樹套平衡樹
題目大意 給定乙個數列,定義兩種操作 1 修改第n個數的值 2 求 l,r 區間內第k大的值。方法 線段樹維護區間,treap樹維護第k大 splay當然也可以 樹套樹第一題。沒想到真的是每個線段樹上的節點建一棵平衡樹。然後修改值就是在所有相關區間內的平衡樹里,erase乙個值再insert乙個值。...