Luogu5354/BZOJ4811 Ynoi2017 由乃的OJ 树链剖分、贪心

传送门

题意:给出一个$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 }

转载于:https://www.cnblogs.com/Itst/p/10046279.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值