luogu3613 睡觉困难综合征

28 篇文章 0 订阅

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[N],lo[N],ro[N];
int c[N][2],n,m,k,fa[N],q[N],top;
bool rev[N];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);update(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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值