2015 Multi-University Training Contest 8 hdu 5390 tree
tree
Time Limit: 8000ms
Memory Limit: 262144KB
This problem will be judged on HDU. Original ID: 539064-bit integer IO format: %I64d Java class name: Main
Given a rooted tree(node 1 is the root) with n nodes. The ithnode has a positive value vi at beginning.
We define the universal set S includes all nodes.
There are two types of Memphis's operation.
First, Memphis may change the value of one node. It's the first type operation:
What's more, Memphis wants to know what's the maxinum of vu⊗vt(t∈path(u,root),⊗ means xor) . It's the second type operation:
View Code
We define the universal set S includes all nodes.
There are two types of Memphis's operation.
First, Memphis may change the value of one node. It's the first type operation:
0 u v (u∈S,0≤v≤109)
What's more, Memphis wants to know what's the maxinum of vu⊗vt(t∈path(u,root),⊗ means xor) . It's the second type operation:
1 u (u∈S)
Input
This problem has multi test cases(no more than 3).
The first line contains a single integer T, which denotes the number of test cases.
For each test case,the first line contains two non-negative integer n,m(1≤n,m≤100000) - the number of nodes and operations.
The second line contains n−1 non-negative integer f2∼fn(fi<i) - the father of ithnode.
The third line contains n non-negative integer v1∼vn(0≤vi≤109) - the value of nodes at beginning.
Follow m lines describe each operation.
The first line contains a single integer T, which denotes the number of test cases.
For each test case,the first line contains two non-negative integer n,m(1≤n,m≤100000) - the number of nodes and operations.
The second line contains n−1 non-negative integer f2∼fn(fi<i) - the father of ithnode.
The third line contains n non-negative integer v1∼vn(0≤vi≤109) - the value of nodes at beginning.
Follow m lines describe each operation.
Output
For each test cases,for each second operation print a non-negative integer.
Sample Input
1 10 10 1 1 2 2 3 1 2 3 5 23512 460943 835901 491571 399045 97756 413210 800843 283274 106134 0 7 369164 0 7 296167 0 6 488033 0 7 187367 0 9 734984 1 6 0 5 329287 1 5 0 7 798656 1 10
Sample Output
766812 351647 431641
Source
解题:看到这位大神的代码后,看了一上午,终于看明白了,真的很神,离线做法,统一查询
先说说为什么要用线段树,因为我们发现是树,树任意两点之间只有唯一的路径,dfs序列,然后更新以后,为什么没有放到叶子结点?因为这是父节点,其代表区间内的任意节点到根的路径,必须经过父节点
所以当然是挂在区间上,而不是放到叶子,那么查询情况呢?我们是从根一直到叶子结点,一直路径上经过的结点,都把查询加入了,因为要查询的结点到根,也是必须经过这些结点的
那么字典树所谓何用,字典树是用来快速求解异或最大值的,利用的是贪心的思想,优先让高位变成1
好啦!代码已经灰常灰常灰常清晰了。。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <vector> 5 #pragma comment(linker, "/STACK:102400000,102400000") 6 using namespace std; 7 const int maxn = 100100; 8 struct arc{ 9 int to,next; 10 arc(int x = 0,int y = -1){ 11 to = x; 12 next = y; 13 } 14 }e[maxn<<1]; 15 struct node{ 16 int val,foo,op; 17 node(int x = 0,int y = 0,int z = 0){ 18 val = x; 19 foo = y; 20 op = z; 21 } 22 }; 23 struct trie{ 24 int tot,root,b[maxn*100][2],cnt[maxn*100]; 25 int newnode(){ 26 b[tot][0] = b[tot][1] = cnt[tot] = 0; 27 return tot++; 28 } 29 void init(){ 30 tot = 0; 31 root = newnode(); 32 } 33 void insert(int val,int f,int root){ 34 for(int i = 30; i >= 0; --i){ 35 int bt = ((val>>i)&1); 36 int &son = bt?b[root][1]:b[root][0]; 37 if(!son) son = newnode(); 38 root = son; 39 cnt[root] += f; 40 } 41 } 42 int query(int val,int root,int ret = 0){ 43 for(int i = 30; i >= 0; --i){ 44 int bt = ((val>>i)&1); 45 int son[2] = {b[root][1],b[root][0]}; 46 if((!son[0] || !cnt[son[0]]) && (!son[1] || !cnt[son[1]])) return 0; 47 if(son[bt] && cnt[son[bt]]){ 48 ret |= (1<<i); 49 root = son[bt]; 50 }else root = son[bt^1]; 51 } 52 return ret; 53 } 54 }T; 55 int head[maxn],L[maxn],R[maxn],ans[maxn],tot,times; 56 vector<node>g[maxn<<2]; 57 void add(int u,int v){ 58 e[tot] = arc(v,head[u]); 59 head[u] = tot++; 60 } 61 void dfs(int u){ 62 L[u] = ++times; 63 for(int i = head[u]; ~i; i = e[i].next) dfs(e[i].to); 64 R[u] = times; 65 } 66 void build(int L,int R,int v){ 67 g[v].clear(); 68 if(L == R) return; 69 int mid = (L + R)>>1; 70 build(L,mid,v<<1); 71 build(mid+1,R,v<<1|1); 72 } 73 void update(int L,int R,int lt,int rt,int val,int f,int v){ 74 if(lt <= L && rt >= R){ 75 g[v].push_back(node(val,f,0)); 76 return; 77 } 78 int mid = (L + R)>>1; 79 if(lt <= mid) update(L,mid,lt,rt,val,f,v<<1); 80 if(rt > mid) update(mid+1,R,lt,rt,val,f,v<<1|1); 81 } 82 void query(int L,int R,int p,int val,int id,int v){ 83 g[v].push_back(node(val,id,1)); 84 if(L == R) return; 85 int mid = (L + R)>>1; 86 if(p <= mid) query(L,mid,p,val,id,v<<1); 87 else query(mid+1,R,p,val,id,v<<1|1); 88 } 89 int val[maxn]; 90 void query(int L,int R,int v){ 91 T.init(); 92 for(int i = 0,sz = g[v].size(); i < sz; ++i){ 93 if(g[v][i].op == 0) T.insert(g[v][i].val,g[v][i].foo,T.root); 94 else ans[g[v][i].foo] = max(ans[g[v][i].foo],T.query(g[v][i].val,T.root)); 95 } 96 if(L == R) return; 97 int mid = (L + R)>>1; 98 query(L,mid,v<<1); 99 query(mid+1,R,v<<1|1); 100 } 101 int main(){ 102 int kase,n,m,fa,op,w; 103 scanf("%d",&kase); 104 while(kase--){ 105 scanf("%d%d",&n,&m); 106 memset(head,-1,sizeof head); 107 times = tot = 0; 108 for(int i = 2; i <= n; ++i){ 109 scanf("%d",&fa); 110 add(fa,i); 111 } 112 dfs(1); 113 build(L[1],R[1],1); 114 for(int i = 1; i <= n; ++i){ 115 scanf("%d",val+i); 116 update(1,n,L[i],R[i],val[i],1,1); 117 } 118 for(int i = 1; i <= m; ans[i++] = -1){ 119 scanf("%d",&op); 120 if(op){ 121 scanf("%d",&fa); 122 query(1,n,L[fa],val[fa],i,1); 123 }else{ 124 scanf("%d%d",&fa,&op); 125 update(1,n,L[fa],R[fa],val[fa],-1,1); 126 val[fa] = op; 127 update(1,n,L[fa],R[fa],op,1,1); 128 } 129 } 130 query(1,n,1); 131 for(int i = 1; i <= m; ++i) 132 if(ans[i] != -1) printf("%d\n",ans[i]); 133 } 134 return 0; 135 }
夜空中最亮的星,照亮我前行