[洛谷]P3613 睡觉困难综合征

题目大意:给出一棵n个点的树,每个点有一个运算符(与、或、异或)和一个数,支持两种操作,第一种修改一个点的运算符和数,第二种给出x,y,z,询问若有一个0~z之间的数从点x走到点y(简单路径),并且对路径上经过的点做对应的运算,最终最大能是多少。(n,操作数<=100,000,数字在[0,2^64)之间)

思路:洛谷改编NOI的一道神题,树剖/LCT维护若一开始全是0/全是1,经过一条链后各位会变成什么,用位运算合并信息,然后每个询问,从高位往低位贪心,每次取0和1中经过这条链后得到的较大值,若相同则取0,总复杂度O(nlogn)/O(nlogn^2)。

#include<cstdio>
#include<algorithm>
using namespace std;
#define ll unsigned long long
inline ll read()
{
    ll x;char c;
    while((c=getchar())<‘0‘||c>‘9‘);
    for(x=c-‘0‘;(c=getchar())>=‘0‘&&c<=‘9‘;)x=(x<<3)+(x<<1)+c-‘0‘;
    return x;
}
#define MN 100000
#define L(x) c[x][0]
#define R(x) c[x][1]
struct edge{int nx,t;}e[MN*2+5];
struct data{ll f[2];}lf[MN+5],rf[MN+5],f[MN+5];
data operator+(const data&a,const data&b)
{
    return (data){~a.f[0]&b.f[0]|a.f[0]&b.f[1],
                  ~a.f[1]&b.f[0]|a.f[1]&b.f[1]};
}
int h[MN+5],en,fa[MN+5],c[MN+5][2],rv[MN+5],z[MN+5],zn;
inline void ins(int x,int y)
{
    e[++en]=(edge){h[x],y};h[x]=en;
    e[++en]=(edge){h[y],x};h[y]=en;
}
void dfs(int x)
{
    for(int i=h[x];i;i=e[i].nx)
        if(e[i].t!=fa[x])fa[e[i].t]=x,dfs(e[i].t);
}
inline void up(int x)
{
    lf[x]=rf[x]=f[x];
    if(L(x))lf[x]=lf[L(x)]+lf[x],rf[x]=rf[x]+rf[L(x)];
    if(R(x))lf[x]=lf[x]+lf[R(x)],rf[x]=rf[R(x)]+rf[x];
}
void init(int x,int o,ll z)
{
    if(o==1)f[x]=(data){0,z};
    if(o==2)f[x]=(data){z,-1};
    if(o==3)f[x]=(data){z,~z};
    up(x);
}
inline void rev(int x){rv[x]^=1;swap(L(x),R(x));swap(lf[x],rf[x]);}
inline void down(int x){if(rv[x])rev(L(x)),rev(R(x)),rv[x]=0;}
inline bool isc(int x){return L(fa[x])==x||R(fa[x])==x;}
void rotate(int x)
{
    int f=fa[x],ff=fa[f],l=R(f)==x,r=l^1;
    if(isc(f))c[ff][R(ff)==f]=x;
    fa[f]=x;fa[x]=ff;fa[c[x][r]]=f;
    c[f][l]=c[x][r];up(c[x][r]=f);
}
void splay(int x)
{
    for(int i=z[zn=1]=x;isc(i);)i=z[++zn]=fa[i];
    for(;zn;--zn)down(z[zn]);
    for(int f;isc(x);rotate(x))
        if(isc(f=fa[x]))rotate(L(fa[f])==f^L(f)==x?x:f);
    up(x);
}
void access(int x)
{
    for(int i=0;x;x=fa[i=x])splay(x),R(x)=i;
}
int main()
{
    int n,m,i,x,u;ll z,ans,f0,f1;
    n=read();m=read();read();
    for(i=1;i<=n;++i)x=read(),init(i,x,read());
    for(i=1;i<n;++i)ins(read(),read());
    dfs(1);
    while(m--)
        if(read()<2)
        {
            access(x=read());splay(x);rev(x);
            access(x=read());splay(x);
            z=read();ans=u=0;
            for(i=64;i--;)
                if(u||(z&(1LLU<<i)))
                {
                    f0=lf[x].f[0]&(1LLU<<i);
                    f1=lf[x].f[1]&(1LLU<<i);
                    if(f0>=f1)u=1;
                    ans|=max(f0,f1);
                }
                else ans|=lf[x].f[0]&(1LLU<<i);
            printf("%llu\n",ans);
        }
        else x=read(),i=read(),splay(x),init(x,i,read());
}
时间: 2024-08-24 23:12:30

[洛谷]P3613 睡觉困难综合征的相关文章

洛谷P2114起床困难综合征

从高位到低位按位枚举,贪心.如果该位填1比填0结果优且填1不会超出m限制,那就填1,否则填0 1 /*by SilverN*/ 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<cmath> 6 using namespace std; 7 const int mxn=100020; 8 int n,m; 9 int p[35]; 10 int op[mxn],a[m

Luogu 睡觉困难综合征 ([NOI2014]起床困难综合症)

一.[NOI2014]起床困难综合症 题目描述 网址:https://daniu.luogu.org/problemnew/show/2114 大意: 有一条链,链上每一个节点包含一个位运算f 与 一个值w , 一个值V从链首出发. 每经过一个点u ,有: \(V = V (f)w\),其中f = {&.|.^}中的一个. 现在限定初始值V在区间\([0,R]\)中,请选定一个值,使得最终结果最大. 题目解法 史上最简单的NOI题目,当时肯定一群大佬秒A. 显然对于二进制,每一位的运算之间没有影

省队集训Day1 睡觉困难综合征

传送门:https://www.luogu.org/problem/show?pid=3613 [题解] 按二进制位分开,对于每一位,用"起床困难综合征"的方法贪心做. 写棵LCT,维护正反两种权值,每个维护2种,代表全0的输出和全1的输出. 然后直接上LCT即可. 权值的合并有点trick,可以参考代码,需要压位. # include <stdio.h> # include <string.h> # include <iostream> # inc

Luogu3613 睡觉困难综合征

题面描述https://www.luogu.org/problemnew/show/3613 原题NOI2014起床困难综合症https://www.luogu.org/problemnew/show/2114做完原题就可以尝试解决这道题目了 题意:一棵n个节点的树,每个节点上有一个位运算操作符(与.或.异或)和一个数字,走过一个点的时候当前值就会和这个数字做相应运算.现在给定x,y,z,要求在[0,z]中选区一个初值使从x点走到y点的最终结果最大.支持动态修改点上的操作符与数字. 我太菜了完全

睡觉困难综合征

为什么每次数据结构题主程序都写挂 #include<cstdio> #include<vector> #include<iostream> #include<algorithm> typedef unsigned long long u64; struct func{ u64 a,b; inline func(u64 x=-1ull,u64 y=0){a=x,b=y;} inline u64 operator()(u64 x)const{return(x&a

洛谷P3938 斐波那契

题目戳 题目描述 小 C 养了一些很可爱的兔子. 有一天,小 C 突然发现兔子们都是严格按照伟大的数学家斐波那契提出的模型来进行 繁衍:一对兔子从出生后第二个月起,每个月刚开始的时候都会产下一对小兔子.我们假定, 在整个过程中兔子不会出现任何意外. 小 C 把兔子按出生顺序,把兔子们从 1 开始标号,并且小 C 的兔子都是 1 号兔子和 1 号兔子的后代.如果某两对兔子是同时出生的,那么小 C 会将父母标号更小的一对优先标 号. 如果我们把这种关系用图画下来,前六个月大概就是这样的: 其中,一个

洛谷P3941入阵曲

洛谷P3941入阵曲 [题目描述] 丹青千秋酿,一醉解愁肠. 无悔少年枉,只愿壮志狂. 小 F 很喜欢数学,但是到了高中以后数学总是考不好. 有一天,他在数学课上发起了呆:他想起了过去的一年.一年前,当他初识算法竞赛的 时候,觉得整个世界都焕然一新.这世界上怎么会有这么多奇妙的东西?曾经自己觉得难以 解决的问题,被一个又一个算法轻松解决. 小 F 当时暗自觉得,与自己的幼稚相比起来,还有好多要学习的呢. 一年过去了,想想都还有点恍惚. 他至今还能记得,某天晚上听着入阵曲,激动地睡不着觉,写题写到

洛谷 P2709 BZOJ 3781 小B的询问

题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表示第i个询问的答案. 输入输出样例 输入样例#1: 6 4 3 1 3 2 1 1 3

洛谷1231 教辅的组成

洛谷1231 教辅的组成 https://www.luogu.org/problem/show?pid=1231 题目背景 滚粗了的HansBug在收拾旧语文书,然而他发现了什么奇妙的东西. 题目描述 蒟蒻HansBug在一本语文书里面发现了一本答案,然而他却明明记得这书应该还包含一份练习题.然而出现在他眼前的书多得数不胜数,其中有书,有答案,有练习册.已知一个完整的书册均应该包含且仅包含一本书.一本练习册和一份答案,然而现在全都乱做了一团.许多书上面的字迹都已经模糊了,然而HansBug还是可