zoukankan      html  css  js  c++  java
  • 可持久化01Tire&DFS序

    字典树,前面的AC自动机里面用的东西

    (01Tire) 可以用来解决 (xor) 问题

    struct{
        int c[N][2],tot;
        int getnode(){
            tot++;
            c[tot][0] = c[tot][1] = 0;
            return tot;
        }    
        void insert(int val){
    	    int u = 0;
    	    for(int i = maxbit;i >= 0;i--){
    	        int v = (val & (1 << i) ) ? 1 : 0;
    	        if(!c[u][v])c[u][v] = getnode();
    	        u = c[u][v];
    	    }
        }
        void init(){
            c[0][0] = c[0][1] = 0;
        	tot = 0;
       	}
    }Tire;
    

    动态开点

    int getnode(){
    	tot++;
    	c[tot][0] = c[tot][1] = 0;
    	return tot;
    }  
    

    动态开点的好处就是在多数数据的时候不需要 memset

    数据插入

    void insert(int val){
    	int u = 0;
    	for(int i = maxbit;i >= 0;i--){
    		int v = (val & (1 << i) ) ? 1 : 0;
    		if(!c[u][v])c[u][v] = getnode();
    		u = c[u][v];
    	}
    }
    

    从高位到低位插入到01字典树中

    01Tire

    HDU-4825 Xor Sum

    给一个集合,每次询问给出 (x) ,输出集合中的数 (k) 使得它们异或最大。

    注意是输出数,不是输出最大的异或值

    思路:

    用集合里的数建 (01Tire) ,将 (x) 按位取反,从高位开始匹配,匹配失败则换一边

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 2e6 + 10;
    const int maxbit = 30; //int不能开31,intmax = (1<<31)-1
    struct{
        int c[N][2],tot;
        
        int getnode(){
            tot++;
            c[tot][0] = c[tot][1] = 0;
            return tot;
        }    
        void insert(int val){
    	    int u = 0;
    	    for(int i = maxbit;i >= 0;i--){
    	        int v = (val & (1 << i) ) ? 1 : 0;
    	        if(!c[u][v])c[u][v] = getnode();
    	        u = c[u][v];
    	    }
        }
    
        int query(int val){
            int u = 0;
            int ans = 0;
    	    for(int i = maxbit;i >= 0;i--){
    	        int v = (val & (1 << i)) ? 0 : 1;
    	        if(!c[u][v]) v ^= 1;
    	        if(v)ans += (1 << i);
    	        
    	        u = c[u][v];
    	    }
    	    return ans;
        }
        void init(){
            c[0][0] = c[0][1] = 0;
        	tot = 0;
       	}
    }Tire;
    
    int n,m,x,T;
    
    int main(){
        scanf("%d",&T);
        for(int c = 1;c <= T;c++){
        	Tire.init();
        	scanf("%d%d",&n,&m);
       	 	for(int i = 0;i < n;i++){
       	     	scanf("%d",&x);
       	     	Tire.insert(x);
    	   	}
    	   	printf("Case #%d:
    ",c);
     	   	for(int i = 0;i < m;i++){
            	scanf("%d",&x);
            	printf("%d
    ",Tire.query(x));
    	   	}
        }
    }
    

    可持久化Tire

    51nod-1295 XOR key

    区间查询

    搞一个可持久化的Tire就好了

    插入:

    // root[i] = insert(root[i-1],v,val);
    int insert(int pre, int v, int val) {
    	int u = getnode();
    	int ans = u;
    	for (int i = maxbit; i >= 0; i--) {
    		c[u][0] = c[pre][0];
    		c[u][1] = c[pre][1]; //复制信息
    		int x = val & (1 << i) ? 1 : 0;
    		c[u][x] = getnode();//开点
    		u = c[u][x]; // 0 是空的节点,所以可以一直这样迭代
    		pre = c[pre][x];
    	}
    	return ans;
    }
    

    其实也很简单,就是复制之前的信息,然后开点。

    查询:

    由于开点是一个一个分配的,所以只要 id < root[l] 就不是区间内

    ,所以只要加上这一个判断就跟之前的一样。

    int query(int l, int r, int x) {
    	int MinID = root[l];
    
    	int u = root[r];
    	int ans = 0;
    	for (int i = maxbit; i >= 0; i--) {
    		int now = (x & (1 << i)) ? 0 : 1;
    		if (c[u][now] and c[u][now] >= MinID) {
    			u = c[u][now];
    			ans += (1 << i);
    		}
    		else {
    			u = c[u][now ^ 1];
    		}
    	}
    	return ans;
    }
    

    完整代码

    /*
     * @Author: zhl
     * @Date: 2020-10-13 09:46:47
     */
    
    
     //                            #@@# .   .,,,.                                   
     //                          /@@@@@&             @@@@@&                         
     //                          /@@@@                 @@@@                         
     //                            /%      *(#%,,,,&%, .@@.                         
     //                            (        ./*   ,*.   %                           
     //                           (          *     ,     .                          
     //                          @@        ,.  .,        @@       @@@@,             
     //                         &@@@@.     ., ,.    .  /@@@@@&&&&@@@@@.             
     //                     @@@@@@@@@@@@#*       .,%@@@@@@@@@@@@@@@@@               
     //                  @@@@@@@, @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                    
     //          .     @@@@@@     @@@@@@@@@@@@@@@@@@@@@@@@@@%%%&%&&@&%@&            
     //     .  .//,   &@@@@        @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#%%&&           
     //       (/,,,  *               @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&%%%@@/          
     //   ((*//,,*  #/&#              @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#%%@@&@@@@@*    
     //    #((###%%%%%#(          .&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%&&@@%/@@@@@@   
     //   %####%%%%%%%%%%,*    @@@@@@@@@#                  @@@@@@@@@&&&@@           
     //   ####%%%%%%%%%%/   @@@@@@@,                       @@@@@@@@@@&&@&           
     //  (##((#%%%%%%%%#    &@@.                          @@&...&%@@@@@&&           
     //  /(((##%%%%%%%%                                             @%,             
     //  /((##%%%%%%%%                                                              
     //        ,#%&%#                                                               
    
    
    #include<bits/stdc++.h>
    using namespace std;
    
    #define rep(i,a,b) for(int i = a;i <= b;i++)
    #define repE(i,u) for(int i = head[u];i;i = E[i].next)
    #define swap(a,b) a^=b,b^=a,a^=b
    
    const int N = 2e6 + 10;
    const int maxbit = 30;
    struct {
    	int root[N], c[N][2], tot;
    	void init() {
    		c[0][0] = c[0][1] = 0;
    		tot = 0;
    		root[0] = 0;
    	}
    	int getnode() {
    		tot++;
    		c[tot][0] = c[tot][1] = 0;
    		return tot;
    	}
    	//root[v] = insret(Tire.root[v-1], v, val);
    	int insert(int pre, int v, int val) {
    		int u = getnode();
    		int ans = u;
    		for (int i = maxbit; i >= 0; i--) {
    			c[u][0] = c[pre][0];
    			c[u][1] = c[pre][1];
    			int x = val & (1 << i) ? 1 : 0;
    			c[u][x] = getnode();
    			u = c[u][x];
    			pre = c[pre][x];
    		}
    		return ans;
    	}
    	int query(int l, int r, int x) {
    		int Treesize = maxbit + 2;
    		int MinID = root[l];
    
    		int u = root[r];
    		int ans = 0;
    		for (int i = maxbit; i >= 0; i--) {
    			int now = (x & (1 << i)) ? 0 : 1;
    			if (c[u][now] and c[u][now] >= MinID) {
    				u = c[u][now];
    				ans += (1 << i);
    			}
    			else {
    				u = c[u][now ^ 1];
    			}
    		}
    		return ans;
    	}
    }Tire;
    
    int n, m, l, r, x;
    int A[N];
    int main() {
    	scanf("%d%d", &n, &m);
    	Tire.init();
    	for (int i = 1; i <= n; i++) {
    		scanf("%d", A + i);
    		Tire.root[i] = Tire.insert(Tire.root[i-1],i,A[i]);
    	}
    	for (int i = 1; i <= m; i++) {
    		scanf("%d%d%d", &x, &l, &r);
    		printf("%d
    ", Tire.query(l + 1, r + 1, x));
    	}
    }
    

    DFS序 + 可持久化Tire

    HDU-6191

    思路:

    DFS序,转化为第二个问题

    dfs序:

    void dfs(int u, int p) {
    	L[u] = ++cnt;
    	val[cnt] = A[u];
    	repE(i, u) {
    		if (E[i].to == p)continue;
    		dfs(E[i].to, u);
    	}
    	R[u] = ++cnt;
    	val[cnt] = A[u];
    }
    

    完整代码:

    /*
     * @Author: zhl
     * @Date: 2020-10-13 11:06:09
     */
    
    
     //                            #@@# .   .,,,.                                   
     //                          /@@@@@&             @@@@@&                         
     //                          /@@@@                 @@@@                         
     //                            /%      *(#%,,,,&%, .@@.                         
     //                            (        ./*   ,*.   %                           
     //                           (          *     ,     .                          
     //                          @@        ,.  .,        @@       @@@@,             
     //                         &@@@@.     ., ,.    .  /@@@@@&&&&@@@@@.             
     //                     @@@@@@@@@@@@#*       .,%@@@@@@@@@@@@@@@@@               
     //                  @@@@@@@, @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                    
     //          .     @@@@@@     @@@@@@@@@@@@@@@@@@@@@@@@@@%%%&%&&@&%@&            
     //     .  .//,   &@@@@        @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#%%&&           
     //       (/,,,  *               @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&%%%@@/          
     //   ((*//,,*  #/&#              @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#%%@@&@@@@@*    
     //    #((###%%%%%#(          .&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%&&@@%/@@@@@@   
     //   %####%%%%%%%%%%,*    @@@@@@@@@#                  @@@@@@@@@&&&@@           
     //   ####%%%%%%%%%%/   @@@@@@@,                       @@@@@@@@@@&&@&           
     //  (##((#%%%%%%%%#    &@@.                          @@&...&%@@@@@&&           
     //  /(((##%%%%%%%%                                             @%,             
     //  /((##%%%%%%%%                                                              
     //        ,#%&%#                                                               
    
    
    #include<bits/stdc++.h>
    using namespace std;
    
    #define rep(i,a,b) for(int i = a;i <= b;i++)
    #define repE(i,u) for(int i = head[u];i;i = E[i].next)
    #define swap(a,b) a^=b,b^=a,a^=b
    
    const int N = 2e5 + 10;
    //cnm 1e6 一直T
    //N 5e5,m 5e5
    
    struct Edge {
    	int to, next;
    }E[N << 1];
    
    int head[N], tot;
    void addEdge(int from, int to) {
    	E[++tot] = Edge{ to,head[from] };
    	head[from] = tot++;
    }
    
    const int maxbit = 30;
    struct {
    	int root[N<<5], c[N<<5][2], tot;
    	void init() {
    		c[0][0] = c[0][1] = 0;
    		tot = 0;
    		root[0] = 0;
    	}
    	int getnode() {
    		tot++;
    		c[tot][0] = c[tot][1] = 0;
    		return tot;
    	}
    	//root[v] = insret(Tire.root[v-1], v, val);
    	int insert(int pre, int v, int val) {
    		int u = getnode();
    		int ans = u;
    		for (int i = maxbit; i >= 0; i--) {
    			c[u][0] = c[pre][0];
    			c[u][1] = c[pre][1];
    			int x = val & (1 << i) ? 1 : 0;
    			c[u][x] = getnode();
    			u = c[u][x];
    			pre = c[pre][x];
    		}
    		return ans;
    	}
    	int query(int l, int r, int x) {
    		int Treesize = maxbit + 2;
    		int MinID = root[r] - Treesize * (r - l);
    
    		int u = root[r];
    		int ans = 0;
    		for (int i = maxbit; i >= 0; i--) {
    			int now = (x & (1 << i)) ? 0 : 1;
    			if (c[u][now] and c[u][now] >= MinID) {
    				u = c[u][now];
    				ans += (1 << i);
    			}
    			else {
    				u = c[u][now ^ 1];
    			}
    		}
    		return ans;
    	}
    }Tire;
    
    int n, q, l, r, x;
    int A[N];
    
    int cnt;
    int val[N << 1], L[N], R[N];
    void dfs(int u, int p) {
    	L[u] = ++cnt;
    	val[cnt] = A[u];
    	repE(i, u) {
    		if (E[i].to == p)continue;
    		dfs(E[i].to, u);
    	}
    	R[u] = ++cnt;
    	val[cnt] = A[u];
    }
    int main() {
    	while (scanf("%d%d", &n, &q) == 2) {
    		memset(head, 0, sizeof(int) * (n + 10));
    		tot = 0; Tire.init();
    
    		for (int i = 1; i <= n; i++) {
    			scanf("%d", A + i);
    		}
    
    		for (int i = 1; i < n; i++) {
    			scanf("%d", &l);
    			addEdge(l, i + 1);
    			addEdge(i + 1, l);
    		}
    
    		cnt = 0;
    		dfs(1, -1);
    
    		for (int i = 1; i <= cnt; i++) {
    			Tire.root[i] = Tire.insert(Tire.root[i - 1], i, val[i]);
    		}
    
    		for (int i = 0; i < q; i++) {
    			scanf("%d%d", &l, &x);
    			printf("%d
    ", Tire.query(L[l], R[l], x));
    		}
    	}
    }
    

    LCA + 可持久化Tire

    洛谷异或

    两种询问,

    1 x z,询问 x 的子树与 z 异或的最大值

    2 x y z,询问路径与 z 异或的最大值

    思路:

    建两颗可持久化Tire,一颗按dfs顺序建,一颗每个点接到它的父节点,也是树型结构。

    void dfs(int u, int p) {
    	id[u] = ++cnt;
    	fa[u][0] = p; dep[u] = dep[p] + 1;
    
    	for (int x = 1; (1 << x) < dep[u]; x++) {
    		fa[u][x] = fa[fa[u][x - 1]][x - 1];
    	}
    
    	Tire1.root[cnt] = Tire1.insert(Tire1.root[cnt - 1], A[u]);
    	Tire2.root[cnt] = Tire2.insert(Tire2.root[id[p]], A[u]);
    	sz[u] = 1;
    	repE(i, u) {
    		int v = E[i].to;
    		if (v == p)continue;
    		dfs(v, u);
    
    		sz[u] += sz[v];
    	}
    }
    

    完整代码

    /*
     * @Author: zhl
     * @Date: 2020-10-14 10:12:23
     */
    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i = a;i <= b;i++)
    #define repE(i,u) for(int i = head[u];i;i = E[i].next)
    using namespace std;
    const int N = 5e5 + 10;
    
    struct Edge {
    	int to, next;
    }E[N << 1];
    
    int head[N], tot;
    void addEdge(int from, int to) {
    	E[++tot] = Edge{ to,head[from] };
    	head[from] = tot++;
    }
    
    int A[N];
    
    int n, m;
    const int maxbit = 30;
    struct {
    	int c[N << 5][2], root[N], tot;
    	int getnode() {
    		tot++;
    		c[tot][0] = c[tot][1] = 0;
    		return tot;
    	}
    	void init() {
    		c[0][0] = c[0][1] = 0;
    		tot = 0;
    	}
    	int insert(int pre, int val) {
    		int u = getnode();
    		int ans = u;
    		for (int i = maxbit; i >= 0; i--) {
    			c[u][0] = c[pre][0];
    			c[u][1] = c[pre][1];
    			int x = val & (1 << i) ? 1 : 0;
    			c[u][x] = getnode();
    			u = c[u][x];
    			pre = c[pre][x];
    		}
    		return ans;
    	}
    	int query(int l, int r, int val) {
    		int minID = root[l];
    		int u = root[r];
    		int ans = 0;
    		for (int i = maxbit; i >= 0; i--) {
    			int now = (val & (1 << i)) ? 0 : 1;
    			if (c[u][now] and c[u][now] >= minID) {
    				ans += (1 << i);
    				u = c[u][now];
    			}
    			else u = c[u][now ^ 1];
    		}
    		return ans;
    	}
    }Tire1, Tire2;
    
    int sz[N], id[N], cnt, fa[N][32], dep[N];
    void dfs(int u, int p) {
    	id[u] = ++cnt;
    	fa[u][0] = p; dep[u] = dep[p] + 1;
    
    	for (int x = 1; (1 << x) < dep[u]; x++) {
    		fa[u][x] = fa[fa[u][x - 1]][x - 1];
    	}
    
    	Tire1.root[cnt] = Tire1.insert(Tire1.root[cnt - 1], A[u]);
    	Tire2.root[cnt] = Tire2.insert(Tire2.root[id[p]], A[u]);
    	sz[u] = 1;
    	repE(i, u) {
    		int v = E[i].to;
    		if (v == p)continue;
    		dfs(v, u);
    
    		sz[u] += sz[v];
    	}
    }
    
    int LCA(int x, int y) {
    	if (dep[x] < dep[y])swap(x, y);
    	while (dep[x] != dep[y]) {
    		int u = dep[x] - dep[y];
    		int v = 0;
    		while (!(u & (1 << v)))v++;
    		x = fa[x][v];
    	}
    
    	while (x != y) {
    		int v = 0;
    		while (fa[x][v] != fa[y][v])v++;
    		x = fa[x][max(0, v - 1)]; y = fa[y][max(0, v - 1)];
    	}
    	return x;
    }
    
    int main() {
    	scanf("%d%d", &n, &m);
    	rep(i, 1, n)scanf("%d", A + i);
    	rep(i, 1, n - 1) {
    		int x, y; scanf("%d%d", &x, &y);
    		addEdge(x, y); addEdge(y, x);
    	}
    	dfs(1, 0);
    	rep(i, 1, m) {
    		int op, a, b, x; scanf("%d", &op);
    		if (op == 1) {
    			scanf("%d%d", &a, &x);
    			printf("%d
    ", Tire1.query(id[a], id[a] + sz[a] - 1, x));
    		}
    		else {
    			scanf("%d%d%d", &a, &b, &x);
    			int u = LCA(a, b);
    			printf("%d
    ", max(Tire2.query(id[u], id[a], x), Tire2.query(id[u], id[b], x)));
    		}
    	}
    }
    

    HDU-4757 Tree

    路径查询

    /*
     * @Author: zhl
     * @Date: 2020-10-14 10:12:23
     */
    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i = a;i <= b;i++)
    #define repE(i,u) for(int i = head[u];i;i = E[i].next)
    using namespace std;
    const int N = 2e5 + 10;
    
    struct Edge {
    	int to, next;
    }E[N << 1];
    
    int head[N], tot;
    void addEdge(int from, int to) {
    	E[++tot] = Edge{ to,head[from] };
    	head[from] = tot++;
    }
    
    int A[N];
    
    int n, m;
    const int maxbit = 30;
    struct {
    	int c[N << 5][2], root[N], tot;
    	int getnode() {
    		tot++;
    		c[tot][0] = c[tot][1] = 0;
    		return tot;
    	}
    	void init() {
    		c[0][0] = c[0][1] = 0;
    		tot = 0;
    	}
    	int insert(int pre, int val) {
    		int u = getnode();
    		int ans = u;
    		for (int i = maxbit; i >= 0; i--) {
    			c[u][0] = c[pre][0];
    			c[u][1] = c[pre][1];
    			int x = val & (1 << i) ? 1 : 0;
    			c[u][x] = getnode();
    			u = c[u][x];
    			pre = c[pre][x];
    		}
    		return ans;
    	}
    	int query(int l, int r, int val) {
    		int minID = root[l];
    		int u = root[r];
    		int ans = 0;
    		for (int i = maxbit; i >= 0; i--) {
    			int now = (val & (1 << i)) ? 0 : 1;
    			if (c[u][now] and c[u][now] >= minID) {
    				ans += (1 << i);
    				u = c[u][now];
    			}
    			else u = c[u][now ^ 1];
    		}
    		return ans;
    	}
    }Tire;
    
    int sz[N], id[N], cnt, fa[N][32], dep[N];
    void dfs(int u, int p) {
    	id[u] = ++cnt;
    	fa[u][0] = p; dep[u] = dep[p] + 1;
    	sz[u] = 1;
    	for (int x = 1; (1 << x) < dep[u]; x++) {
    		fa[u][x] = fa[fa[u][x - 1]][x - 1];
    	}
    
    	Tire.root[cnt] = Tire.insert(Tire.root[id[p]], A[u]);
    
    	repE(i, u) {
    		int v = E[i].to;
    		if (v == p)continue;
    		dfs(v, u);
    
    		sz[u] += sz[v];
    	}
    }
    
    int LCA(int x, int y) {
    	if (dep[x] < dep[y])swap(x, y);
    	while (dep[x] != dep[y]) {
    		int u = dep[x] - dep[y];
    		int v = 0;
    		while (!(u & (1 << v)))v++;
    		x = fa[x][v];
    	}
    
    	while (x != y) {
    		int v = 0;
    		while (fa[x][v] != fa[y][v])v++;
    		x = fa[x][max(0, v - 1)]; y = fa[y][max(0, v - 1)];
    	}
    	return x;
    }
    
    int main() {
    	while (~scanf("%d%d", &n, &m)) {
    		Tire.init();
    		tot = 0;
    		cnt = 0;
    		rep(i, 1, n) {
    			head[i] = 0;
    			memset(fa[i], 0, sizeof(fa[i]));
    		}
    		rep(i, 1, n)scanf("%d", A + i);
    		rep(i, 1, n - 1) {
    			int x, y; scanf("%d%d", &x, &y);
    			addEdge(x, y); addEdge(y, x);
    		}
    		dfs(1, 0);
    		rep(i, 1, m) {
    			int a, b, x;
    			scanf("%d%d%d", &a, &b, &x);
    			int u = LCA(a, b);
    			printf("%d
    ", max(Tire.query(id[u], id[a], x), Tire.query(id[u], id[b], x)));
    		}
    	}
    }
    
  • 相关阅读:
    循环逗号分割数组!
    只是想好好学习一下!
    html元素水平垂直居中
    闭包知识点--笔记
    20160314
    从零开始做运维-零
    Nginx 和 CodeIgniter
    安装PIL库
    init
    NutUI3 多端实践之路
  • 原文地址:https://www.cnblogs.com/sduwh/p/13809827.html
Copyright © 2011-2022 走看看