Description

给定一棵 \(n\) 个点的树,每个点上有位运算 \(opt\) 和一个权值 \(x\),位运算有 &,|,^ 三种。

要求支持:

  1. 修改点 \(v\) 的 \(opt\) 和 \(x_v\)
  2. 确定一个初始点权在 \([0,z]\) 之间的 \(v_0\),然后依次经过从 \(x\) 到 \(y\) 的所有节点。每经过一个节点 \(i\), \(v\) 就变成 \(v\;opt\;x_i\) 请回答最后到 \(y\) 时可能的最大的 \(v\) 。

Solution

首先五十分的做法比较显然,就是拆位建 \(lct\),然后每位分开做,复杂度 \(O(nk\log n)\)。

这样只有 \(50\) 分,考虑优化复杂度。

因为 \(O(n\log n)\) 已经是 \(lct\) 的复杂度了不是很能优化掉,考虑去掉复杂度乘上的 \(k\)。

有这个 \(k\) 的原因是我们对于每一位都搞了棵 \(lct\) 出来。如果我们只弄一棵 \(lct\) 是否可行呢?

定义 \(f0,f1\) 分别为初始值全 \(0/1\) 走过一条路径之后的答案

那在 \(lct\) 中需要维护的就是 \(splay\) 里 \(x\) 的子树,中序遍历的 \(f0,f1\) 已经倒着的中序遍历(与中序遍历相反)\(f0,f1\) (要维护这个倒着的原因是当前点 \(x\) 的值与左右子树的顺序有关,而 \(splay\) 中又有 \(reverse\) 操作所以要维护)。

那有了这个能不能快速更新呢?也就是说有左区间的 \(f0,f1\) 和右区间的 \(g0,g1\),能不能快速求出来 \(h0,h1\) 呢?废话

更新式子比较显然就是:\(h0=(f0\&g1)+(\sim f0\& g0),h1=(f1\And g1)+(\sim f1\& g0)\)

证明的话就是全 \(0\) 放进去左区间之后跑出来的是 \(f0\),可能长 \(10010001010\) 这样,然后再去 $\And $ 一下 \(g1\) 就代表这些当前为 \(1\) 的位放进右区间之后跑出来的是多少。因为 \(\&\) 了 \(f0\) 所以最后答案肯定不会比 \(f0\) 大。其它几项的证明也类似就不去证了。

最后求出来 从 \(x\) 到 \(y\) 的 \(f0,f1\) 之后贪心的选就好了。

Code

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<cctype>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using std::min;
using std::max;
using std::swap;
using std::vector;
typedef double db;
typedef unsigned long long ll;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define all(A) A.begin(),A.end()
#define mp(A,B) std::make_pair(A,B) namespace NewweN{ const int N=1e5+5; int n,m,cnt,head[N],stk[N],top;
int fa[N],ch[N][2],tag[N],k;ll maxn;
char buf[1048578];int ptr,MX;
#define ls ch[x][0]
#define rs ch[x][1] struct Edge{
int to,nxt;
}edge[N<<1]; void add(int x,int y){
edge[++cnt].to=y;
edge[cnt].nxt=head[x];
head[x]=cnt;
} struct Node{
ll a,b;
Node(){}
Node(ll x,ll y){
a=x,b=y;
}
friend Node operator+(Node x,Node y){
return Node((x.a&y.b)+(((~x.a))&y.a),(x.b&y.b)+(((~x.b))&y.a));
}
}l[N],r[N],val[N]; char nc(){
if(ptr==MX) MX=fread(buf,1,1<<20,stdin),ptr=0;
return ptr==MX?EOF:buf[ptr++];
}
#define getchar nc
ll getint(){
ll X=0,w=0;char ch=getchar();
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while( isdigit(ch))X=X*10+ch-48,ch=getchar();
if(w) return -X;return X;
} void dfs(int now,int f=0){
for(int i=head[now];i;i=edge[i].nxt){
int to=edge[i].to;
if(to==f)continue;
fa[to]=now;
dfs(to,now);
}
} void pushup(int x){
l[x]=r[x]=val[x];
if(ls)l[x]=l[ls]+l[x],r[x]=r[x]+r[ls];
if(rs)l[x]=l[x]+l[rs],r[x]=r[rs]+r[x];
} void pushr(int x){
tag[x]^=1;swap(ls,rs);swap(l[x],r[x]);
} void pushdown(int x){
if(tag[x])tag[x]=0,pushr(ls),pushr(rs);
} bool nroot(int x){
return ch[fa[x]][0]==x or ch[fa[x]][1]==x;
} void rotate(int x){
int y=fa[x],z=fa[y],d=ch[y][1]==x,dd=ch[z][1]==y;
ch[y][d]=ch[x][d^1];if(ch[x][d^1])fa[ch[x][d^1]]=y;
fa[x]=z;if(nroot(y))ch[z][dd]=x;
fa[y]=x;ch[x][d^1]=y;pushup(y);
} void splay(int x){
int now=x;stk[++top]=now;
while(nroot(now))now=fa[now],stk[++top]=now;
while(top)pushdown(stk[top--]);
while(nroot(x)){
int y=fa[x],z=fa[y];
if(nroot(y))rotate((ch[y][1]==x)^(ch[z][1]==y)?x:y);
rotate(x);
}pushup(x);
} void access(int x){
for(int y=0;x;y=x,x=fa[x]){
splay(x);rs=y;
pushup(x);
}
} void makeroot(int x){
access(x),splay(x),pushr(x);
} void split(int x,int y){
makeroot(x),access(y),splay(y);
} signed main(){
n=getint(),m=getint(),k=getint();
maxn=(1ull<<k)-1;
for(int i=1;i<=n;i++){
ll x=getint(),y=getint();
if(x==1)val[i]=Node(0,y);
if(x==2)val[i]=Node(y,~0);
if(x==3)val[i]=Node(y,(~y));
}
for(int i=1;i<n;i++){
int x=getint(),y=getint();
add(x,y),add(y,x);
} dfs(1);
while(m--){
int opt=getint(),x=getint(),y=getint();ll z=getint();
if(opt==1){
split(x,y);
ll ans=0,used=0;
for(int i=k-1;~i;i--){
if(l[y].a>>i&1ull) ans|=1ull<<i;
else if((l[y].b>>i&1ull) and (used|(1ull<<i))<=z) ans|=1ull<<i,used|=1ull<<i;
} printf("%llu\n",ans);
} else{
splay(x);
if(y==1) val[x]=Node(0,z);
if(y==2) val[x]=Node(z,~0);
if(y==3) val[x]=Node(z,(~z));
pushup(x);
}
} return 0;
}
} int yzh=NewweN::main(); signed main(){return 0;}

[Luogu 3613] 睡觉困难综合征的更多相关文章

  1. 洛谷3613睡觉困难综合征(LCT维护链信息(前后缀)+贪心)

    这个题目还是很好啊QWQ很有纪念意义 首先,如果在序列上且是单次询问的话,就是一个非常裸的贪心了QWQ这也是NOI当时原题的问题和数据范围 我们考虑上树的话,应该怎么做? 我的想法是,对于每一位建一个 ...

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

    一.[NOI2014]起床困难综合症 题目描述 网址:https://daniu.luogu.org/problemnew/show/2114 大意: 有一条链,链上每一个节点包含一个位运算f 与 一 ...

  3. 【刷题】洛谷 P3613 睡觉困难综合征

    题目背景 刚立完Flag我就挂了WC和THUWC... 时间限制0.5s,空间限制128MB 因为Claris大佬帮助一周目由乃通过了Deus的题,所以一周目的由乃前往二周目世界找雪辉去了 由于二周目 ...

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

    传送门:https://www.luogu.org/problem/show?pid=3613 [题解] 按二进制位分开,对于每一位,用“起床困难综合征”的方法贪心做. 写棵LCT,维护正反两种权值, ...

  5. Luogu3613 睡觉困难综合征/BZOJ4811 Ynoi2017 由乃的OJ 树链剖分、贪心

    传送门 题意:给出一个$N$个点的树,树上每个点有一个位运算符号和一个数值.需要支持以下操作:修改一个点的位运算符号和数值,或者给出两个点$x,y$并给出一个上界$a$,可以选取一个$[0,a]$内的 ...

  6. 洛谷P3613 睡觉困难综合征(LCT,贪心)

    洛谷题目传送门 膜拜神犇出题人管理员!!膜拜yler和ZSY!! 没错yler连续教我这个蒟蒻写起床困难综合症和睡觉困难综合症%%%Orz,所以按位贪心的思路可以继承下来 这里最好还是写树剖吧,不过我 ...

  7. 洛谷P3613 睡觉困难综合征(LCT)

    题目: P3613 睡觉困难综合症 解题思路: LCT,主要是维护链上的多位贪心答案,推个公式:分类讨论入0/1的情况,合并就好了(公式是合并用的) 代码(我不知道之前那个为啥一直wa,改成结构体就好 ...

  8. Luogu3613 睡觉困难综合征

    题面描述https://www.luogu.org/problemnew/show/3613 原题NOI2014起床困难综合症https://www.luogu.org/problemnew/show ...

  9. [bzoj3668][Noi2014]起床困难综合症/[洛谷3613]睡觉困难综合症

    来自FallDream的博客,未经允许,请勿转载,谢谢. 21 世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳.作为一名青春阳光好少年,atm 一直坚持与起床困难综 ...

随机推荐

  1. java多线程系列5 atomic简介

    先看一个例子,AtomicInteger 实现的线程安全的累加器 public class AtomicIntTest { public static void main(String[] args) ...

  2. 通过flask的request对象获取url

    测试了一下:通过发送 GET 到 http://127.0.0.1:5000/test/a?x=1, 后台输出为(官网说明): 1 request.path: /test/a 2 request.ho ...

  3. To me

    1.流泪的时候不做任何决定: 2.不反复思考同一个问题: 3.不害怕做错什么: 4.有负面情绪是正常的: 5.一切的烦恼都是自找的: 6.说过的话一定要做到: 7.不要去害怕做一件事: 8.无论是对是 ...

  4. 深入C#的String类

  5. memmove、memcpy和memccpy简介

    memmove.memcpy和memccpy三个函数都是内存的拷贝,从一个缓冲区拷贝到另一个缓冲区.memmove(void *dest,void*src,int count)memcpy(void ...

  6. Mingw下载

    http://ismdeep.oss-cn-shenzhen.aliyuncs.com/x86_64-5.3.0-release-posix-seh-rt_v4-rev0.7z

  7. php判断语句

    编写代码时,可以为不同的情况执行不同的动作.可以使用判断条件语句来实现. if...else...elseif 例子一: <?php $t=date("H"); if ($t ...

  8. git-创建新项目

    1.一般第一次使用git,需要进行全局设置,如果下次创建新项目或者fork别人的项目,则不需要再进行设置:但是如果想要提交到不同的代码管理网站,则需要再设置,比如现在我的是在gitlab.com上进行 ...

  9. PHP字符串函数之 strpos stripos strrpos strripos

    strpos – 查找字符串首次出现的位置 stripos – 查找字符串首次出现的位置(不区分大小写) strrpos – 计算指定字符串在目标字符串中最后一次出现的位置 strripos – 计算 ...

  10. 《pyhton语言程序设计》_第一章笔记

    章1.62 (1).python区分大小写. (2).python忽略在符号#之后的同行的内容 (3).python和matlab很相似(个人感觉) (4).章节1.91: >>>i ...