以每個結點為根,建一顆字典樹(內容為1到i的值)。這樣之後,做差後,即為一段區間或是一段路徑。
可以發現,如果裸著建,不僅要消耗很多的時間,更是要消耗很多的空間。考慮以i為根的字典樹和以(i-1)為跟的字典樹的異同。
可以發現,在當前以i為根的字典樹上減去a[i],就是(i-1)的字典樹了。所以,我們可以將除了a[i]之外的結點都連到(i-1)的樹上。
當然,i-1的樹也是從i-2的樹上引用過來的。
這樣之後,會出現乙個問題。比如,a[i-1]的值與a[i]的值相同,那麼我們到底要不要跟新呢?還是直接將root[i]全部指向root[i-1]?
還是之前的做法。除了a[i]的值,其他的值全部引用前面的,將a[i]跟新root[i]。
這樣做完之後,可以發現,如果不加以區分,root[i]和root[i-1]的樹一模一樣,直接做差之後不就沒有了。可是事實上,在【i,i】這給區間內,有乙個數的值為a[i]。
所以我們用乙個sum陣列加以區別,也就是說,如果當前的root的結點是引用前面的,那麼sum不變。否則(就是a[i]跟新的部分),sum[root[i]]=sum[[root[i-1]]+1。a[i]這個數的每個位置都是之前的+1。
這樣我們在判斷區間的時候,就可以拿sum[root[r]]-sum[root[l-1]]。如果大於0,說明在root[l-1]之後,被跟新過,所以可以取。如果sum值相同,代表root[r]中的那部分是直接引用的root[l-1]中的那部分,這個區間內沒有跟新過,所以無法取。
//要查詢的是sum[n]^sum[k-1]^x 最大。//從k開始異或,那麼l-1<=k-1<=r-1 所以看以r-1為根的樹是在以l-2為根的樹上跟新過
// 所以應該是root[r],root[l-1]
#include"stdio.h"
#define n 30050000
int tree[n][2];
int root[n];
int l;
int sum[n];
int d[40];
int cnt;
void split(int k)
for (i=l+1;i<=27;i++) d[i]=0;
return;
}void build(int x,int &y)
}int query(int x,int y) else
} return ans;
}char s[10];
int main()
for (i=1;i<=m;i++) else
}}
模板 可持久化字典樹
made by xiper updata time 2015 12 8 test status 使用前呼叫初始化函式 init 同時 root 0 0 struct trie persistent tree triesize 獲取字符集雜湊編號 必須在 0 lettersize 之內 inline ...
dfs序 可持久化字典樹
query on a tree 題意 有一顆樹,有n個節點,每個節點都有權值,有q次詢問,每次詢問以u為根的子樹節點權值中異或x結果最大的值。題解 首先解決u為根子樹節點的問題,直接dfs序,解決異或,用字典樹,但是同時用的話,就需要用可持久化字典樹,其實就是字首樹。這題學習到一波可持久化字典樹。i...
bzoj4546 可持久化字典樹
可持久化字典樹模板題。把每個數轉換成二進位制建立字典樹,按照下標建立可持久化字典樹,存一下子樹中點的個數就行了。1 include2 include3 include4 include5 using namespace std 6 inline char nc 12return p1 13 14 i...