洛谷传送门
题目描述
因为Claris大佬帮助一周目由乃通过了Deus的题,所以一周目的由乃前往二周目世界找雪辉去了
由于二周目世界被破坏殆尽,所以由乃和雪辉天天都忙着重建世界(其实和MC差不多吧),Deus看到了题问她,总是被告知无可奉告
Deus没办法只能去三周目世界问三周目的由乃OI题。。。
三周目的世界中,因为没有未来日记,所以一切都很正常,由乃天天认真学习。。。
因为Deus天天问由乃OI题,所以由乃去学习了一下OI
由于由乃智商挺高,所以OI学的特别熟练
她在RBOI2016中以第一名的成绩进入省队,参加了NOI2016获得了金牌保送
Deus:这个题怎么做呀?
yuno:这个不是NOI2014的水题吗。。。
Deus:那如果出到树上,多组链询问,带修改呢?
yuno:诶。。。???
Deus:这题叫做睡觉困难综合征哟~
虽然由乃OI很好,但是她基本上不会DS,线段树都只会口胡,比如她NOI2016的分数就是100+100+100+0+100+100。。。NOIP2017的分数是100+0+100+100+0+100
所以她还是只能找你帮她做了。。。
题目描述
由乃这个问题越想越迷糊,已经达到了废寝忘食的地步。结果她发现……晚上睡不着了!只能把自己的一个神经元(我们可以抽象成一个树形结构)拿出来,交给Deus。
这个神经元是一个有n个点的树,每个点的包括一个位运算 和一个权值 ,位运算有&,l,^三种,分别用 表示。
为了治疗失眠,Deus可以将一些神经递质放在点x上,初始的刺激值是 。然后 依次经过从 到 的所有节点,每经过一个点 , 就变成 ,所以他想问你,最后到 时,希望得到的刺激值尽可能大,所以最大值的 可以是多少呢?当然由于初始的神经递质的量有限,所以给定的初始值 必须是在 之间。Deus每次都会给你3个数, 。
不过,Deus为了提升治疗效果,可能会对一些神经节点进行微调。在这种情况下,也会给三个数 , , ,意思是把 点的操作修改为 ,数值改为 。
输入输出格式
输入格式:
第一行三个数 , , 。 的意义是每个点上的数,以及询问中的数值 < ,。之后 行,每行两个数 表示该点的位运算编号以及数值
之后 行,每行两个数 表示 和 之间有边相连
之后 行,每行四个数, 表示这次操作为 ( 为询问, 为更改), , , 意义如题所述。
输出格式:
对于每个操作1,输出到最后可以造成的最大刺激度v。
输入输出样例
输入样例#1:
5 5 3
1 7
2 6
3 7
3 6
3 1
1 2
2 3
3 4
1 5
1 1 4 7
1 1 3 5
2 1 1 3
2 3 3 3
1 1 3 2
输出样例#1:
7
1
5
输入样例#2:
2 2 2
2 2
2 2
1 2
2 2 2 2
1 2 2 2
输出样例#2:
3
说明
对于 的数据,
对于另外 的数据,
对于另外 的数据,位运算只会出现一种
对于 的数据, , ,
解题分析
要做这道题, 首先需要做这道题:起床困难综合症 蒟蒻此题题解。然后我们就会发现这道题只是把所有贪心操作搬到了树上, 所以我们只要在合理复杂度内能够提出链来就可以
贪心A题啦….
然后我们发现, 似乎提出一段链的操作LCT可以很容易办到, 那么很容易想到用LCT维护子树中按dfs序操作的一段序列。 但只维护从小到大dfs序的操作还不行, 因为涉及到翻转操作, 翻转时左右顺序正好相反。所以我们同时还需要维护从大到小的操作。
现在我们考虑如何合并左右两端区间操作的结果。 设左半部分每位取0进行操作后的答案为
, 取1进行操作后的答案为
, 右半部分每位取0进行操作后的答案为
, 取1进行操作后的答案为
, 合并后结果为
。显然, 如果我们每位取0进行左半部分操作后答案一部分将会变成1, 这部分数位在进入右半部分计算时结果为
的对应数位。同理, 仍为0的一部分进入右半部分计算时结果等于
的对应数位。 所以我们可得:
同理可得
剩下的就是打板贼6了…
PS:此题需要开
才能过, 而
的输出方法为
或
。
PPS:博主因为
的
里面没有
, 导致WA的莫名奇妙(如果
没有
将会忽略后面所有的
操作, 直接执行完所有情况), 主要是数据正好有
只有一种操作(操作3), 还A了4个点…博主查了半天都没查出来QAQ…
代码如下:
#include <cstdio>
#include <algorithm>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <limits.h>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 200005
#define ll unsigned long long
#define ls tree[now].son[0]
#define rs tree[now].son[1]
#define dad tree[now].fat
template <typename T>
IN void in(T &x)
{
R bool fu = false;
x = 0; R char c = gc;
W (!isdigit(c)) {if(c == '-') fu = true; c = gc;}
W (isdigit(c))
x = (x << 1) + (x << 3) + c - 48, c = gc;
if(fu) x = -x;
}
struct Message
{ll val0, valk;};
struct Node
{
int son[2], fat;
bool rev;
Message lef, rig, ori;
}tree[MX];
int dot, q, top, dgt;
int st[MX];
ll mul[70];
namespace LCT
{
IN void modify(const int &now, const ll &zero, const ll &kth)
{
tree[now].ori.val0 = tree[now].lef.val0 = tree[now].rig.val0 = zero;
tree[now].ori.valk = tree[now].rig.valk = tree[now].lef.valk = kth;
}
IN bool get(const int &now) {return tree[dad].son[1] == now;}
IN bool nroot(const int &now) {return tree[dad].son[0] == now || tree[dad].son[1] == now;}
IN Message operator + (const Message &lef, const Message &rig)
{
Message ret;
ret.val0 = (~lef.val0 & rig.val0) | (lef.val0 & rig.valk);
ret.valk = (~lef.valk & rig.val0) | (lef.valk & rig.valk);
return ret;
}
IN void pushrev(const int &now)
{
tree[now].rev ^= 1;
std::swap(ls, rs);
std::swap(tree[now].lef, tree[now].rig);//不要忘了此处需要互换
}
IN void pushup(const int &now)
{
tree[now].lef = tree[now].rig = tree[now].ori;
if(ls) tree[now].lef = tree[ls].lef + tree[now].lef, tree[now].rig = tree[now].rig + tree[ls].rig;
if(rs) tree[now].lef = tree[now].lef + tree[rs].lef, tree[now].rig = tree[rs].rig + tree[now].rig;
}
IN void pushdown(const int &now)
{
if(tree[now].rev)
{
if(ls) pushrev(ls);
if(rs) pushrev(rs);
tree[now].rev = false;
}
}
IN void rotate(const int &now)
{
R bool dir = get(now);
R int fa = dad, grand = tree[fa].fat;
tree[fa].son[dir] = tree[now].son[dir ^ 1];
tree[tree[now].son[dir ^ 1]].fat = fa;
if(nroot(fa)) tree[grand].son[get(fa)] = now;
tree[now].fat = grand;
tree[now].son[dir ^ 1] = fa;
tree[fa].fat = now;
pushup(fa);
}
IN void splay(const int &now)
{
R int fa, grand, x = now; top = 0;
st[++top] = x;
W (nroot(x)) x = tree[x].fat, st[++top] = x;
W (top) pushdown(st[top--]);
W (nroot(now))
{
fa = dad, grand = tree[fa].fat;
if(nroot(fa)) rotate(get(now) == get(fa) ? fa : now);
rotate(now);
}
pushup(now);
}
IN void access(R int now)
{
for (R int x = 0; now; x = now, now = dad)
splay(now), rs = x, pushup(now);
}
IN void makeroot(const int &now)
{access(now), splay(now), pushrev(now);}
IN void split(const int &x, const int &y)
{makeroot(x), access(y), splay(y);}
IN void link(const int &x, const int &y)
{makeroot(x); tree[x].fat = y;}
IN ll query(const int &from, const int &to, const ll &up)
{
ll cost = 0, ans = 0;
split(from, to);
for (R int i = dgt - 1; ~i; --i)
{
if(tree[to].lef.val0 & mul[i]) {ans |= mul[i]; continue;}//split后to的dfs序最大, 所以应该查正向dfs序的答案
if((tree[to].lef.valk & mul[i]) && up >= (cost | mul[i])) cost |= mul[i], ans |= mul[i];
}
return ans;
}
}
int main(void)
{
ll a, b, c, typ;
in(dot), in(q), in(dgt);
for (R int i = 0; i < dgt; ++i) mul[i] = 1ull << i;
for (R int i = 1; i <= dot; ++i)
{
in(a), in(b);
switch(a)
{
case 1: LCT::modify(i, 0ull, b); break;
case 2: LCT::modify(i, b, ~0ull); break;
case 3: LCT::modify(i, b, ~b); break;
}
}
for (R int i = 1; i < dot; ++i)
{
in(a), in(b);
LCT::link(a, b);
}
W (q--)
{
in(typ);
if(typ & 1)
{
in(a), in(b), in(c);
printf("%llu\n", LCT::query(a, b, c));
}
else
{
in(a), in(b), in(c);
LCT::makeroot(a);
switch(b)
{
case 1: LCT::modify(a, 0ull, c); break;
case 2: LCT::modify(a, c, ~0ull); break;//不要忘了break!
case 3: LCT::modify(a, c, ~c); break;
}
LCT::pushup(a);
}
}
}