Luogu3613 睡觉困难综合征

原题链接:https://www.luogu.org/problemnew/show/P3613

睡觉困难综合征

题目背景

刚立完Flag我就挂了WC和THUWC。。。

时间限制0.5s,空间限制128MB

因为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个点的树,每个点的包括一个位运算opt和一个权值x,位运算有&,l,^三种,分别用1,2,3表示。

为了治疗失眠,Deus可以将一些神经递质放在点x上,初始的刺激值是 v 0 v_0 v0 。然后v依次经过从x到y的所有节点,每经过一个点i,v就变成v opti xi,所以他想问你,最后到y时,希望得到的刺激值尽可能大,所以最大值的v可以是多少呢?当然由于初始的神经递质的量有限,所以给定的初始值 v 0 v_0 v0必须是在[0,z]之间。Deus每次都会给你3个数,x,y,z。

不过,Deus为了提升治疗效果,可能会对一些神经节点进行微调。在这种情况下,也会给三个数x,y,z,意思是把x点的操作修改为y,数值改为z。

输入输出格式
输入格式:

第一行三个数n,m,k。k的意义是每个点上的数,以及询问中的数值z都 &lt; 2 k &lt;2^k <2k。之后n行,每行两个数x,y表示该点的位运算编号以及数值。

之后n - 1行,每行两个数x,y表示x和y之间有边相连。

之后m行,每行四个数,Q,x,y,z表示这次操作为Q(1位询问,2为更改),x,y,z意义如题所述。

输出格式:

对于每个操作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

说明

对于30%的数据,n,m <= 1

对于另外20%的数据,k <= 5

对于另外20%的数据,位运算只会出现一种

对于100%的数据,0 <= n , m <= 100000 , k <= 64

题解

蒟蒻我一开始以为位运算什么的顺序不会有影响,样例都没玩就开始打, W A \mathcal{WA} WA成傻逼。。。

所以说,这道题最妙的地方就是, L C T \mathcal{LCT} LCT里维护的东西是对顺序有要求的,不同于和或者最大值是无序的。所以我们需要维护 S p l a y \mathcal{Splay} Splay里全 0 0 0串和全 1 1 1串中序遍历做完所有操作的结果的结果(为啥维护这个东西详见起床困难综合征)。

那么如何合并两个结果呢???

其实很简单,我们只需要把前面跑完后的是 0 0 0的地方跟后面的全 0 0 0串跑完的结果合并;同理,将 1 1 1的地方跟后面的全 1 1 1串合并。

0 0 0串的合并与全 1 1 1都是差不多的。

给出代码,配合理解:

sd merge(sd a,sd b)
{return (sd){(~a.s0&b.s0)|(a.s0&b.s1),(~a.s1&b.s0)|(a.s1&b.s1)};}

其他的就跟普通 L C T \mathcal{LCT} LCT起床困难综合征大同小异了,看代码即可。

代码
#include<bits/stdc++.h>
#define inf ULONG_LONG_MAX
#define ls son[v][0]
#define rs son[v][1]
#define ll unsigned long long
using namespace std;
const int M=1e5+5;
struct sd{ll s0,s1;}val[M],ab[M],ba[M];
sd merge(sd a,sd b){return (sd){(~a.s0&b.s0)|(a.s0&b.s1),(~a.s1&b.s0)|(a.s1&b.s1)};}
int son[M][2],dad[M],n,m,k;
bool rev[M];
void swap(sd &a,sd &b){sd c=a;a=b;b=c;}
bool notroot(int v){return son[dad[v]][0]==v||son[dad[v]][1]==v;}
void up(int v)
{
	ab[v]=ba[v]=val[v];
	if(ls)ab[v]=merge(ab[ls],ab[v]),ba[v]=merge(ba[v],ba[ls]);
	if(rs)ab[v]=merge(ab[v],ab[rs]),ba[v]=merge(ba[rs],ba[v]);
}
void turn(int v){swap(ab[v],ba[v]);swap(ls,rs);rev[v]^=1;}
void down(int v){if(rev[v]){if(ls)turn(ls);if(rs)turn(rs);rev[v]=0;}}
void push(int v){if(notroot(v))push(dad[v]);down(v);}
void spin(int v)
{
	int f=dad[v],ff=dad[f],k=son[f][1]==v,w=son[v][!k];
	if(notroot(f))son[ff][son[ff][1]==f]=v;son[v][!k]=f;son[f][k]=w;
	if(w)dad[w]=f;dad[f]=v;dad[v]=ff;
	up(f);
}
void splay(int v)
{
	push(v);int f,ff;
	while(notroot(v))
	{
		f=dad[v],ff=dad[f];
		if(notroot(f))spin((son[f][0]==v)^(son[ff][0]==f)?v:f);
		spin(v);
	}
	up(v);
}
void access(int v){for(int f=0;v;v=dad[f=v])splay(v),rs=f,up(v);}
void beroot(int v){access(v);splay(v);turn(v);}
void get(ll v,ll a,ll b)
{
	switch(a)
	{
		case 1:val[v]=(sd){0ull,b};break;
		case 2:val[v]=(sd){b,inf};break;
		case 3:val[v]=(sd){b,~b};
	}
}
void in()
{
	ll a,b;
	scanf("%d%d%d",&n,&m,&k);--k;
	for(int i=1;i<=n;++i){scanf("%llu%llu",&a,&b);get(i,a,b);}
	for(int i=1;i<n;++i){scanf("%llu%llu",&a,&b);beroot(a);dad[a]=b;}
}
ll work(ll a,ll b,ll c)
{
	beroot(a);access(b);splay(b);
	ll p0=ab[b].s0,p1=ab[b].s1,p,ans=0ull,w=0ull;
	for(int i=k;i>=0;--i)
	{
		p=1ull<<i;
		if(p0&p)ans+=p;
		else if((c>=p)&&(p1&p))ans+=p,c-=p;
	}
	return ans;
}
void ac()
{
	ll op,a,b,c;
	for(int i=1;i<=m;++i)
	{
		scanf("%llu%llu%llu%llu",&op,&a,&b,&c);
		if(op==1)printf("%llu\n",work(a,b,c));
		else splay(a),get(a,b,c),up(a);
	}
}
int main(){in();ac();}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值