洛谷 3613 - 睡觉困难综合征

该题是[NOI2014]起床困难综合征的树上加修改版

先说说《起床困难综合征》,由于不同位运算之间不满足交换律,故必须按顺序执行操作

考虑位运算套路 —— 拆位,对于未知的初始值,它的每一位也是未知的,所以可以用两个变量 $a_0, a_1$ 来当作初始值当前位为 $0$ 或 $1$ 时最终可以得到的值,最后贪心即可

附上部分代码:

 1 int a1 = 0, a2 = - 1;
 2 for (int i = 1; i <= N; i ++) {
 3     scanf ("%s", opt + 1);
 4     int p = getnum ();
 5     if (opt[1] == 'A')
 6         a1 &= p, a2 &= p;
 7     else if (opt[1] == 'O')
 8         a1 |= p, a2 |= p;
 9     else if (opt[1] == 'X')
10         a1 ^= p, a2 ^= p;
11 }
12 int ps = 0, ans = 0;
13 for (int j = 30; j >= 1; j --) {
14     if (a1 & (1 << (j - 1)))
15         ans += (1 << (j - 1));
16     else if ((a2 & (1 << (j - 1))) && ps + (1 << (j - 1)) <= M)
17         ans += (1 << (j - 1)), ps += (1 << (j - 1));
18 }

那么现在将操作扩展到树上,使用 $LCT$ 来维护其代表的链的 $a_0, a_1$ ,通过找规律可以发现:

设新的 $a_0, a_1$ 分别为 $f_0, f_1$ ,旧的分别为 $x.a_0, x.a_1$ 及 $y.a_0, y.a_1$ (其中 $x, y$ 为从左往右),现在要合并 $x, y$

对于 $f_0$ 很好想到要将 $x.a_0 \ opt \ y.a_0$ 与 $x.a_0 \ opt \ y.a_1$ 合并即可得解,公式即为 $(x.a_0 \& y.a_1) | (~ x.a_0 \& y.a_0)$ ,其中, $(x.a_0 \& y.a_t)$ 为通解,第二个的取反即为消去 $x.a_0$ 中为 $1$ 的位对第二个操作的影响

$pushup$ 写完就是 $LCT$ 常规操作了,求答案也是贪心即可

注意:由于有 $makeroot$ 操作,又求答案顺序一定是从左往右,所以还需要维护一下从右往左的答案,用于在 $reverse$ 的时候交换

代码

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 
  5 using namespace std;
  6 
  7 typedef long long LL;
  8 typedef unsigned long long uLL;
  9 
 10 const int MAXN = 1e05 + 10;
 11 
 12 // {&, |, ^} -> {1, 2, 3}
 13 int opt[MAXN]= {0};
 14 LL value[MAXN]= {0};
 15 
 16 struct optionSt {
 17     LL a0, a1;
 18 
 19     optionSt () {}
 20     optionSt (LL fa0, LL fa1) :
 21         a0 (fa0), a1 (fa1) {}
 22 
 23 } ;
 24 optionSt merge (optionSt x, optionSt y) {
 25     LL f0 = ((x.a0 & y.a1) | (~ x.a0 & y.a0));
 26     LL f1 = ((x.a1 & y.a1) | (~ x.a1 & y.a0));
 27     return optionSt (f0, f1);
 28 }
 29 /*pair<LL, LL> merge (pair<LL, LL> p1, pair<LL, LL> p2) {
 30     LL a00 = p1.first, a10 = p1.second;
 31     LL a01 = p2.first, a11 = p2.second;
 32     LL a0 = ((a00 & a11) | (~ a00 & a01));
 33     LL a1 = ((a10 & a11) | (~ a10 & a01));
 34     return make_pair (a0, a1);
 35 }*/
 36 optionSt calc (int op, LL val) {
 37     switch (op) {
 38         case 1:
 39             return optionSt (0ll, val);
 40         case 2:
 41             return optionSt (val, - 1ll);
 42         case 3:
 43             return optionSt (val, ~ val);
 44     }
 45 }
 46 
 47 int father[MAXN]= {0};
 48 int son[MAXN][2]= {0};
 49 optionSt tval[MAXN], froml[MAXN], fromr[MAXN];
 50 int revtag[MAXN]= {0};
 51 
 52 int isroot (int p) {
 53     return son[father[p]][0] != p && son[father[p]][1] != p;
 54 }
 55 int sonbel (int p) {
 56     return son[father[p]][1] == p;
 57 }
 58 void reverse (int p) {
 59     if (! p)
 60         return ;
 61     swap (son[p][0], son[p][1]);
 62     swap (froml[p], fromr[p]); // 注意要更改左右顺序
 63     revtag[p] ^= 1;
 64 }
 65 void pushup (int p) {
 66     froml[p] = fromr[p] = tval[p];
 67     if (son[p][0]) {
 68         froml[p] = merge (froml[son[p][0]], froml[p]);
 69         fromr[p] = merge (fromr[p], fromr[son[p][0]]);
 70     }
 71     if (son[p][1]) {
 72         froml[p] = merge (froml[p], froml[son[p][1]]);
 73         fromr[p] = merge (fromr[son[p][1]], fromr[p]);
 74     }
 75 }
 76 void pushdown (int p) {
 77     if (revtag[p]) {
 78         reverse (son[p][0]), reverse (son[p][1]);
 79         revtag[p] = 0;
 80     }
 81 }
 82 void rotate (int p) {
 83     int fa = father[p], anc = father[fa];
 84     int s = sonbel (p);
 85     son[fa][s] = son[p][s ^ 1];
 86     if (son[fa][s])
 87         father[son[fa][s]] = fa;
 88     if (! isroot (fa))
 89         son[anc][sonbel (fa)] = p;
 90     father[p] = anc;
 91     son[p][s ^ 1] = fa, father[fa] = p;
 92     pushup (fa), pushup (p);
 93 }
 94 int Stack[MAXN];
 95 int top = 0;
 96 void splay (int p) {
 97     top = 0, Stack[++ top] = p;
 98     for (int nd = p; ! isroot (nd); nd = father[nd])
 99         Stack[++ top] = father[nd];
100     while (top > 0)
101         pushdown (Stack[top]), top --;
102     for (int fa = father[p]; ! isroot (p); rotate (p), fa = father[p])
103         if (! isroot (fa))
104             sonbel (p) == sonbel (fa) ? rotate (fa) : rotate (p);
105     pushup (p);
106 }
107 void Access (int p) {
108     for (int tp = 0; p; tp = p, p = father[p])
109         splay (p), son[p][1] = tp, pushup (p);
110 }
111 void Makeroot (int p) {
112     Access (p), splay (p), reverse (p);
113 }
114 void Split (int x, int y) {
115     Makeroot (x);
116     Access (y), splay (y);
117 }
118 void link (int x, int y) {
119     Makeroot (x);
120     father[x] = y;
121 }
122 
123 int N, M, K;
124 
125 uLL Query (int x, int y, LL lim) {
126     Split (x, y);
127     uLL ans = 0, ps = 0;
128     LL a0 = froml[y].a0, a1 = froml[y].a1;
129     for (int j = K; j >= 1; j --) {
130         if (a0 & (1ll << (j - 1)))
131             ans += (1ll << (j - 1));
132         else if ((a1 & (1ll << (j - 1))) && ps + (1ll << (j - 1)) <= lim)
133             ans += (1ll << (j - 1)), ps += (1ll << (j - 1));
134     }
135     return ans;
136 }
137 
138 int getint () {
139     int num = 0;
140     char ch = getchar ();
141 
142     while (! isdigit (ch))
143         ch = getchar ();
144     while (isdigit (ch))
145         num = (num << 3) + (num << 1) + ch - '0', ch = getchar ();
146 
147     return num;
148 }
149 LL getLL () {
150     LL num = 0;
151     char ch = getchar ();
152 
153     while (! isdigit (ch))
154         ch = getchar ();
155     while (isdigit (ch))
156         num = (num << 3) + (num << 1) + ch - '0', ch = getchar ();
157 
158     return num;
159 }
160 uLL getuLL () {
161     uLL num = 0;
162     char ch = getchar ();
163 
164     while (! isdigit (ch))
165         ch = getchar ();
166     while (isdigit (ch))
167         num = (num << 3) + (num << 1) + ch - '0', ch = getchar ();
168 
169     return num;
170 }
171 void work (uLL x) {
172     if (x >= 10)
173         work (x / 10);
174     putchar (x % 10 + '0');
175 }
176 void println (uLL x) {
177     work (x), puts ("");
178 }
179 
180 int main () {
181     N = getint (), M = getint (), K = getint ();
182     for (int i = 1; i <= N; i ++) {
183         opt[i] = getint (), value[i] = getLL ();
184         tval[i] = calc (opt[i], value[i]);
185     }
186     for (int i = 1; i < N; i ++) {
187         int u = getint (), v = getint ();
188         link (u, v);
189     }
190     for (int Case = 1; Case <= M; Case ++) {
191         int op = getint ();
192         if (op == 1) {
193             int x = getint (), y = getint ();
194             uLL lim = getLL ();
195             println (Query (x, y, lim));
196         }
197         else if (op == 2) {
198             int p = getint (), nopt = getint ();
199             LL delta = getLL ();
200             Access (p), splay (p);
201             opt[p] = nopt, value[p] = delta;
202             tval[p] = calc (opt[p], value[p]);
203             pushup (p);
204         }
205     }
206 
207     return 0;
208 }
209 
210 /*
211 5 5 3
212 1 7
213 2 6
214 3 7
215 3 6
216 3 1
217 1 2
218 2 3
219 3 4
220 1 5
221 1 1 4 7
222 1 1 3 5
223 2 1 1 3
224 2 3 3 3
225 1 1 3 2
226 */
227 
228 /*
229 2 2 2
230 2 2
231 2 2
232 1 2
233 2 2 2 2
234 1 2 2 2
235 */

 

转载于:https://www.cnblogs.com/Colythme/p/10221732.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值