题意:给出一个$N$个点的树,树上每个点有一个位运算符号和一个数值。需要支持以下操作:修改一个点的位运算符号和数值,或者给出两个点$x,y$并给出一个上界$a$,可以选取一个$[0,a]$内的整数值,在从$x$到$y$的路径上,每走到一个点就与这个点对应的数值进行对应的位运算,求到达$y$点时数字的可能的最大值。$N,\text{操作数} \leq 10^5$,数字在$unsigned long long$范围内。
可以先去做NOI2014的起床困难综合征
考虑用起床困难综合征的贪心策略加上树链剖分解决这道题。首先我们需要解决一个问题:在起床困难综合征中,我们每一次枚举一位,就整个跑一边,看当前位取$1$是否会产生更大的贡献;但是在这一道题中显然是不能每一次都跑一边的。我们需要快速地维护每一位为$0$或$1$时这一位运算之后得到的答案。因为每一位之间是不相互冲突的,所以我们可以将$2^{64}-1$和$0$分别带入求解,这样第$i$位为$1$时的贡献就是带入$2^{64}-1$时第$i$位的值,而第$i$位为$0$时的贡献就是带入$0$时第$i$位的值。
接下来我们考虑如何用线段树维护这两个值。可以知道在合并的时候,当前这个区间带入$2^{64}-1$的值时的答案就是左边一半带入$2^{64}-1$时的答案再带到右边得到的答案,$0$同理。所以也可以用位运算很快的表示出来,不是很有思路的可以去看下面的$merge$
然后我们就可以树链剖分然后跳跳跳了。
注意一个细节:因为链可以不是直上直下的,在往上的过程中$dfs$序是在变小的,而在往下的过程中在变大,所以在线段树中需要同时维护从左往右和从右往左计算的值(也就是下面的$ltor$和$rtol$)。
1 #include<bits/stdc++.h> 2 #define ull unsigned long long 3 #define lch (now << 1) 4 #define rch (now << 1 | 1) 5 #define mid ((l + r) >> 1) 6 //This code is written by Itst 7 using namespace std; 8 9 inline ull read(){ 10 ull a = 0; 11 char c = getchar(); 12 while(c != EOF && !isdigit(c)) 13 c = getchar(); 14 while(c != EOF && isdigit(c)){ 15 a = (a << 3) + (a << 1) + (c ^ '0'); 16 c = getchar(); 17 } 18 return a; 19 } 20 21 const int MAXN = 100010; 22 struct node{ 23 ull ltor[2] , rtol[2] , val; 24 int op; 25 node(){ 26 ltor[0] = rtol[0] = -1; 27 ltor[1] = rtol[1] = 0; 28 } 29 }Tree[MAXN << 2]; 30 struct Edge{ 31 int end , upEd; 32 }Ed[MAXN << 1]; 33 int head[MAXN] , ind[MAXN] , rk[MAXN] , dep[MAXN] , top[MAXN] , fa[MAXN] , size[MAXN] , son[MAXN] , op[MAXN]; 34 ull num[MAXN]; 35 int ts , N , M , cntEd , K; 36 37 inline ull calc(ull a , ull b , int op){ 38 switch(op){ 39 case 1: 40 return a & b; 41 case 2: 42 return a | b; 43 case 3: 44 return a ^ b; 45 } 46 } 47 48 inline void addEd(int a , int b){ 49 Ed[++cntEd].end = b; 50 Ed[cntEd].upEd = head[a]; 51 head[a] = cntEd; 52 } 53 54 void dfs1(int x , int f){ 55 fa[x] = f; 56 dep[x] = dep[f] + 1; 57 size[x] = 1; 58 for(int i = head[x] ; i ; i = Ed[i].upEd) 59 if(Ed[i].end != f){ 60 dfs1(Ed[i].end , x); 61 size[x] += size[Ed[i].end]; 62 if(size[son[x]] < size[Ed[i].end]) 63 son[x] = Ed[i].end; 64 } 65 } 66 67 void dfs2(int x , int t){ 68 top[x] = t; 69 ind[x] = ++ts; 70 rk[ts] = x; 71 if(!son[x]) 72 return; 73 dfs2(son[x] , t); 74 for(int i = head[x] ; i ; i = Ed[i].upEd) 75 if(Ed[i].end != fa[x] && Ed[i].end != son[x]) 76 dfs2(Ed[i].end , Ed[i].end); 77 } 78 79 inline node merge(node l , node r){ 80 node t; 81 t.ltor[0] = (l.ltor[0] & r.ltor[0]) | (~l.ltor[0] & r.ltor[1]); 82 t.ltor[1] = (l.ltor[1] & r.ltor[0]) | (~l.ltor[1] & r.ltor[1]); 83 t.rtol[0] = (r.rtol[0] & l.rtol[0]) | (~r.rtol[0] & l.rtol[1]); 84 t.rtol[1] = (r.rtol[1] & l.rtol[0]) | (~r.rtol[1] & l.rtol[1]); 85 return t; 86 } 87 88 void init(int now , int l , int r){ 89 if(l == r){ 90 Tree[now].op = op[rk[l]]; 91 Tree[now].val = num[rk[l]]; 92 Tree[now].ltor[0] = Tree[now].rtol[0] = calc(-1 , Tree[now].val , Tree[now].op); 93 Tree[now].ltor[1] = Tree[now].rtol[1] = calc(0 , Tree[now].val , Tree[now].op); 94 } 95 else{ 96 init(lch , l , mid); 97 init(rch , mid + 1 , r); 98 Tree[now] = merge(Tree[lch] , Tree[rch]); 99 } 100 } 101 102 void modify(int now , int l , int r , int tar){ 103 if(l == r){ 104 Tree[now].op = op[rk[l]]; 105 Tree[now].val = num[rk[l]]; 106 Tree[now].ltor[0] = Tree[now].rtol[0] = calc(-1 , Tree[now].val , Tree[now].op); 107 Tree[now].ltor[1] = Tree[now].rtol[1] = calc(0 , Tree[now].val , Tree[now].op); 108 } 109 else{ 110 if(mid >= tar) 111 modify(lch , l , mid , tar); 112 else 113 modify(rch , mid + 1 , r , tar); 114 Tree[now] = merge(Tree[lch] , Tree[rch]); 115 } 116 } 117 118 node query(int now , int l , int r , int L , int R){ 119 if(l >= L && r <= R) 120 return Tree[now]; 121 node p; 122 if(mid >= L) 123 p = merge(p , query(lch , l , mid , L , R)); 124 if(mid < R) 125 p = merge(p , query(rch , mid + 1 , r , L , R)); 126 return p; 127 } 128 129 inline void work(int x , int y , ull maxN){ 130 node l , r; 131 int tx = top[x] , ty = top[y]; 132 while(tx != ty) 133 if(dep[tx] > dep[ty]){ 134 l = merge(query(1 , 1 , N , ind[tx] , ind[x]) , l); 135 x = fa[tx]; 136 tx = top[x]; 137 } 138 else{ 139 r = merge(query(1 , 1 , N , ind[ty] , ind[y]) , r); 140 y = fa[ty]; 141 ty = top[y]; 142 } 143 if(dep[x] > dep[y]) 144 l = merge(query(1 , 1 , N , ind[y] , ind[x]) , l); 145 else 146 r = merge(query(1 , 1 , N , ind[x] , ind[y]) , r); 147 swap(l.rtol[0] , l.ltor[0]); 148 swap(l.rtol[1] , l.ltor[1]); 149 l = merge(l , r); 150 ull ans = 0 , now = 0; 151 for(int i = K - 1 ; i >= 0 ; --i){ 152 ull t = (ull)1 << i , p = l.ltor[0] & t , q = l.ltor[1] & t; 153 if(q >= p || now + t > maxN) 154 ans += q; 155 else{ 156 now += t; 157 ans += p; 158 } 159 } 160 printf("%llu\n" , ans); 161 } 162 163 int main(){ 164 #ifndef ONLINE_JUDGE 165 freopen("3613.in" , "r" , stdin); 166 //freopen("3613.out" , "w" , stdout); 167 #endif 168 N = read(); 169 M = read(); 170 K = read(); 171 for(int i = 1 ; i <= N ; ++i){ 172 op[i] = read(); 173 num[i] = read(); 174 } 175 for(int i = 1 ; i < N ; ++i){ 176 int a = read() , b = read(); 177 addEd(a , b); 178 addEd(b , a); 179 } 180 dfs1(1 , 0); 181 dfs2(1 , 1); 182 init(1 , 1 , N); 183 int o , x , y; 184 ull z; 185 while(M--){ 186 o = read(); 187 x = read(); 188 y = read(); 189 z = read(); 190 if(o == 1) 191 work(x , y , z); 192 else{ 193 op[x] = y; 194 num[x] = z; 195 modify(1 , 1 , N , ind[x]); 196 } 197 } 198 return 0; 199 }