您的位置:首页 > 其它

luogu3613 睡觉困难综合征

2018-03-09 21:28 429 查看
http://www.elijahqi.win/2018/03/09/luogu3613/

题目背景

刚立完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

v0​ 。然后v依次经过从x到y的所有节点,每经过一个点i,v就变成v opti xi,所以他想问你,最后到y时,希望得到的刺激值尽可能大,所以最大值的v可以是多少呢?当然由于初始的神经递质的量有限,所以给定的初始值

v_0

v0​ 必须是在[0,z]之间。Deus每次都会给你3个数,x,y,z。

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

输入输出格式

输入格式:

第一行三个数n,m,k。k的意义是每个点上的数,以及询问中的数值z都

<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

很早之前就看到过和起床困难综合症分不清

还是考虑按位贪心 具体参考起床起床困难综合症

需要回答询问的时候就把这条链切出来询问即可

那么怎么维护这个题解提供了一种简洁的方法 我把信息分开维护 维护lo.f0 表示从左起一开始全是0的一直做操作到我这个位置的信息 lo.f1表示左起一开始全是1的一直操作到我这里 ro同理

假如说我们有两段带合并的已经计算出答案的区间,分别对应f0,f1和g0,g1。我们设合并后的答案是h0,h1,那么有如下式子:

h0=(~f0&g0)+(f0&g1)

h1=(~f1&g0)+(f1&g1)

原因嘛 我分类讨论了下 发现大概是把一些0和1的情况模拟位运算过程分开处理了

注意 维护信息的时候需要有序维护 并且需要判断子树是否为空

#include<cstdio>
#include<algorithm>
#define ll unsigned long long
#define N 110000
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline ll read(){
ll x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=gc();}
while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
return x*f;
}
struct node{
ll f0,f1;
inline friend node operator +(const node &a,const node &b){
node tmp;
tmp.f0=(~a.f0&b.f0)|(a.f0&b.f1);
tmp.f1=(~a.f1&b.f0)|(a.f1&b.f1);return tmp;
}
}v
,lo
,ro
;
int c
[2],n,m,k,fa
,q
,top;
bool rev
;ll bin[70];
inline bool isroot(int x){
return c[fa[x]][1]!=x&&c[fa[x]][0]!=x;
}
inline void update(int x){
int l=c[x][0],r=c[x][1];lo[x]=ro[x]=v[x];
if (l) lo[x]=lo[l]+lo[x],ro[x]=ro[x]+ro[l];
if (r) ro[x]=ro[r]+ro[x],lo[x]=lo[x]+lo[r];
}
inline void revs(int x){
rev[x]^=1;swap(lo[x],ro[x]);swap(c[x][0],c[x][1]);
}
inline void pushdown(int x){
if (!rev[x]) return;rev[x]^=1;
revs(c[x][0]);revs(c[x][1]);
}
inline void rotate(int x){
int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;
if (!isroot(y)) c[z][c[z][1]==y]=x;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;update(y);upd
10004
ate(x);
}
inline void splay(int x){
q[top=1]=x;for (int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];
while(top) pushdown(q[top--]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if (!isroot(y)){
if (c[y][0]==x^c[z][0]==y) rotate(x);else rotate(y);
}rotate(x);
}
}
inline void access(int x){for (int t=0;x;t=x,x=fa[x]) splay(x),c[x][1]=t,update(x);}
inline void makeroot(int x){access(x);splay(x);revs(x);}
inline void split(int x,int y){makeroot(x);access(y);splay(y);}
inline void link(int x,int y){makeroot(x);fa[x]=y;}
inline void change(int i,ll a,ll b){
v[i].f0=lo[i].f0=ro[i].f0=a;
v[i].f1=lo[i].f1=ro[i].f1=b;
}
int main(){
freopen("luogu3613.in","r",stdin);
n=read();m=read();k=read();
for (int i=0;i<k;++i) bin[i]=1llu<<i;
for (int i=1;i<=n;++i){
int op=read();ll z=read();
if (op==1) change(i,0,z);
if (op==2) change(i,z,~0);
if (op==3) change(i,z,~z);
}
for (int i=1;i<n;++i) {int x=read(),y=read();link(x,y);}
while(m--){
int op=read(),x=read(),y=read();ll z=read();
if (op==1){
ll ans=0;split(x,y);
for (int i=k-1;~i;--i){
if (lo[y].f0&bin[i]) {ans+=bin[i];continue;}
if (lo[y].f1&bin[i]&&bin[i]<=z) ans+=bin[i],z-=bin[i];
}printf("%llu\n",ans);
}
if(op==2){
splay(x);op=y;
if (op==1) change(x,0,z);
if (op==2) change(x,z,~0);
if (op==3) change(x,z,~z);update(x);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: