来自FallDream的博客,未经允许,请勿转载,谢谢。


21 世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳。作为一名青春阳光好少年,atm 一直坚持与起床困难综合症作斗争。通过研究相关文献,他找到了该病的发病原因:在深邃的太平洋海底中,出现了一条名为 drd 的巨龙,它掌握着睡眠之精髓,能随意延长大家的睡眠时间。正是由于 drd 的活动,起床困难综合症愈演愈烈,以惊人的速度在世界上传播。为了彻底消灭这种病,atm 决定前往海底,消灭这条恶龙。历经千辛万苦,atm 终于来到了 drd 所在的地方,准备与其展开艰苦卓绝的战斗。drd 有着十分特殊的技能,他的防御战线能够使用一定的运算来改变他受到的伤害。具体说来,drd 的防御战线由 n扇防御门组成。每扇防御门包括一个运算op和一个参数t,其中运算一定是OR,XOR,AND中的一种,参数则一定为非负整数。如果还未通过防御门时攻击力为x,则其通过这扇防御门后攻击力将变为x op t。最终drd 受到的伤害为对方初始攻击力x依次经过所有n扇防御门后转变得到的攻击力。由于atm水平有限,他的初始攻击力只能为0到m之间的一个整数(即他的初始攻击力只能在0,1,...,m中任选,但在通过防御门之后的攻击力不受 m的限制)。为了节省体力,他希望通过选择合适的初始攻击力使得他的攻击能让 drd 受到最大的伤害,请你帮他计算一下,他的一次攻击最多能使 drd 受到多少伤害。

n<=100000 m<=10^9

题解:每一位可以分开计算,结果可以合并,所以我们考虑用线段树把维护起来,开两个数组表示这一位分别是0/1经过这区间的变化之后变成什么,这样就可以O(k)合并。

当然,还有更简单的办法,你可以开4个bitset(或者直接开int),分别表示0/1进去变成0/1的位,这样合并时候就是一顿乱或和与(当然,你可以发现其实两个bitset是相反的,可以选择只开两个,然后用取反)。(这两个速度差不多,有的点你快有的点我快,玄学。)这样合并复杂度降低成k/32(O(1))

#include<iostream>
#include<cstdio>
#include<bitset>
#define ll long long
#define MN 100000
#define MK 30
#define INF (1<<31)-1
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
} struct node{
bitset<MK+> s[][];
int l,r;
}T[MN*+];
char op[MN+][];
int n,m,t[MN+]; void update(int x)
{
int l=x<<,r=x<<|;
T[x].s[][]=(T[l].s[][]&T[r].s[][])|(T[l].s[][]&T[r].s[][]);
T[x].s[][]=(T[l].s[][]&T[r].s[][])|(T[l].s[][]&T[r].s[][]);
T[x].s[][]=(T[l].s[][]&T[r].s[][])|(T[l].s[][]&T[r].s[][]);
T[x].s[][]=(T[l].s[][]&T[r].s[][])|(T[l].s[][]&T[r].s[][]);
} void build(int x,int l,int r)
{
if((T[x].l=l)==(T[x].r=r))
{
if(op[T[x].l][]=='A')
for(int i=;i<=MK;i++)
{
T[x].s[][][i]=;
T[x].s[][(t[T[x].l]&(<<i))>][i]=;
}
else if(op[T[x].l][]=='O')
for(int i=;i<=MK;i++)
{
T[x].s[][][i]=;
T[x].s[][(t[T[x].l]&(<<i))>][i]=;
}
else
for(int i=;i<=MK;i++)
if(t[T[x].l]&(<<i))
T[x].s[][][i]=T[x].s[][][i]=;
else
T[x].s[][][i]=T[x].s[][][i]=;
return;
}
int mid=l+r>>;
build(x<<,l,mid);build(x<<|,mid+,r);
update(x);
} int main()
{
n=read();m=read();
for(int i=;i<=n;i++)
{
scanf("%s",op[i]+);
t[i]=read();
}
build(,,n);int ans=;
for(int i=MK;i>=;i--)
{
if((<<i)<=m&&T[].s[][][i]&&!T[].s[][][i]) ans+=<<i,m-=<<i;
else if(T[].s[][][i]) ans+=<<i;
}
printf("%d\n",ans);
return ;
}

洛谷那道题是它的强化版,首先变成了一棵树,每个节点都有一个符号和数字,支持修改,查询路径,数字<2^64。

这样的话,可以还是选择线段树做法,加一个树剖,或者直接lct维护一下就行了,合并选择bitset<64>或者unsigned long long。

前者期望复杂度qlogn(loglogn) 后者复杂度qlogn但是自带大常数,ditoly大神写的linkcuttree,实际速度差不多(其实还比我慢一些233)

代码有点丑(给大家讲个笑话,我写树剖都没算深度,然后无限T,我以为是复杂度问题,各种卡常数技巧都用上了)

#include<iostream>
#include<cstdio>
#include<bitset>
#define getchar() (*S++)
#define ll unsigned long long
#define MN 100000
#define MK 63
#define pa pair<int,int>
#define mp(x,y) make_pair(x,y)
char B[<<],*S=B;
using namespace std;
inline ll llread()
{
ll x = ; char ch = getchar();
while(ch < '' || ch > '') ch = getchar();
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x;
} inline int read()
{
int x = ; char ch = getchar();
while(ch < '' || ch > '') ch = getchar();
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x;
}
int L[MN*+],R[MN*+];
struct node{
ll s[][];
ll x[][];
}T[MN*+],ans,a;
int op[MN+];
int n,m,z,dn=,tp1,tp2,dfn[MN+],top[MN+],dep[MN+],num[MN+],size[MN+],mx[MN+],fa[MN+],head[MN+],cnt=;
struct edge{int to,next;}e[MN*+];
ll t[MN+];
pa q[MN+],q2[MN+]; inline void ins(int f,int t)
{
e[++cnt]=(edge){t,head[f]};head[f]=cnt;
e[++cnt]=(edge){f,head[t]};head[t]=cnt;
} void update(const node&c)
{
a.s[][]=(ans.s[][]&c.s[][])|(ans.s[][]&c.s[][]);
a.s[][]=(ans.s[][]&c.s[][])|(ans.s[][]&c.s[][]);
a.s[][]=(ans.s[][]&c.s[][])|(ans.s[][]&c.s[][]);
a.s[][]=(ans.s[][]&c.s[][])|(ans.s[][]&c.s[][]);
ans=a;
} void update2(const node&c)
{
a.s[][]=(ans.s[][]&c.x[][])|(ans.s[][]&c.x[][]);
a.s[][]=(ans.s[][]&c.x[][])|(ans.s[][]&c.x[][]);
a.s[][]=(ans.s[][]&c.x[][])|(ans.s[][]&c.x[][]);
a.s[][]=(ans.s[][]&c.x[][])|(ans.s[][]&c.x[][]);
ans=a;
} void update(int x)
{
int l=x<<,r=l|;
T[x].s[][]=(T[l].s[][]&T[r].s[][])|(T[l].s[][]&T[r].s[][]);
T[x].s[][]=(T[l].s[][]&T[r].s[][])|(T[l].s[][]&T[r].s[][]);
T[x].s[][]=(T[l].s[][]&T[r].s[][])|(T[l].s[][]&T[r].s[][]);
T[x].s[][]=(T[l].s[][]&T[r].s[][])|(T[l].s[][]&T[r].s[][]);
T[x].x[][]=(T[r].x[][]&T[l].x[][])|(T[r].x[][]&T[l].x[][]);
T[x].x[][]=(T[r].x[][]&T[l].x[][])|(T[r].x[][]&T[l].x[][]);
T[x].x[][]=(T[r].x[][]&T[l].x[][])|(T[r].x[][]&T[l].x[][]);
T[x].x[][]=(T[r].x[][]&T[l].x[][])|(T[r].x[][]&T[l].x[][]);
} void init(int x,int k)
{
T[x].s[][]=T[x].s[][]=T[x].s[][]=T[x].s[][]=;
if(op[k]==)
for(register int i=;i<=MK;i++)
T[x].s[][]|=1LLU<<i,T[x].s[][(t[k]&(1LLU<<i))>]|=1LLU<<i;
else if(op[k]==)
for(register int i=;i<=MK;i++)
T[x].s[][]|=1LLU<<i,T[x].s[][(t[k]&(1LLU<<i))>]|=1LLU<<i;
else
for(register int i=;i<=MK;i++)
if((t[k]&(1LLU<<i))>)
T[x].s[][]|=(1LLU<<i),T[x].s[][]|=(1LLU<<i);
else
T[x].s[][]|=(1LLU<<i),T[x].s[][]|=(1LLU<<i);
T[x].x[][]=T[x].s[][];
T[x].x[][]=T[x].s[][];
T[x].x[][]=T[x].s[][];
T[x].x[][]=T[x].s[][];
} void build(int x,int l,int r)
{
if((L[x]=l)==(R[x]=r))
{
init(x,num[l]);
return;
}
int mid=l+r>>;
build(x<<,l,mid);build(x<<|,mid+,r);
update(x);
} void renew(int x,int k)
{
if(L[x]==R[x])
{
init(x,num[L[x]]);
return;
}
int mid=L[x]+R[x]>>;
if(k<=mid) renew(x<<,k);
else renew(x<<|,k);
update(x);
} void dfs1(int x,int f)
{
fa[x]=f;size[x]=;mx[x]=;
for(int i=head[x];i;i=e[i].next)
if(e[i].to!=f)
{
dep[e[i].to]=dep[x]+;
dfs1(e[i].to,x);
size[x]+=size[e[i].to];
if(size[e[i].to]>size[mx[x]]) mx[x]=e[i].to;
}
} void dfs2(int x,int tp)
{
top[x]=tp;dfn[x]=++dn;num[dn]=x;
if(mx[x]) dfs2(mx[x],tp);
for(int i=head[x];i;i=e[i].next)
if(e[i].to!=fa[x]&&e[i].to!=mx[x])
dfs2(e[i].to,e[i].to);
} void query(int x,int l,int r)
{
if(L[x]==l&&R[x]==r) {update(T[x]);return;}
int mid=L[x]+R[x]>>;
if(r<=mid) query(x<<,l,r);
else if(l>mid) query(x<<|,l,r);
else query(x<<,l,mid),query(x<<|,mid+,r);
} void query2(int x,int l,int r)
{
if(L[x]==l&&R[x]==r) {update2(T[x]);return;}
int mid=L[x]+R[x]>>;
if(r<=mid) query2(x<<,l,r);
else if(l>mid) query2(x<<|,l,r);
else query2(x<<|,mid+,r),query2(x<<,l,mid);
} void solve(int x,int y,ll t)
{
tp1=tp2=;
ans.s[][]=ans.s[][]=-;
ans.s[][]=ans.s[][]=;
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])
{
q[++tp1]=mp(dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
else
{
q2[++tp2]=mp(dfn[top[y]],dfn[y]);
y=fa[top[y]];
}
}
for(int i=;i<=tp1;i++) query2(,q[i].first,q[i].second);
if(dfn[x]>dfn[y]) query2(,dfn[y],dfn[x]);
else query(,dfn[x],dfn[y]);
for(int i=tp2;i;i--) query(,q2[i].first,q2[i].second);
ll sum=;
for(register int i=MK;i>=;i--)
{
ll th=(1LLU<<i);
if(th<=t&&(ans.s[][]&(1LLU<<i))&&!(ans.s[][]&(1LLU<<i))) sum+=th,t-=th;
else if(ans.s[][]&(1LLU<<i)) sum+=th;
}
printf("%llu\n",sum);
} int main()
{
fread(B,,<<,stdin);
n=read();m=read();z=read();
for(register int i=;i<=n;i++)
op[i]=read(),t[i]=llread();
for(register int i=;i<n;i++)
{
register int u=read(),v=read();
ins(u,v);
}
dfs1(,);dfs2(,);
build(,,n);
for(register int i=;i<=m;i++)
{
int opt=read(),x=read(),y=read();ll z=llread();
if(opt==) solve(x,y,z);
else {op[x]=y;t[x]=z;renew(,dfn[x]);}
}
return ;
}

[bzoj3668][Noi2014]起床困难综合症/[洛谷3613]睡觉困难综合症的更多相关文章

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

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

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

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

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

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

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

    题目大意:给出一棵n个点的树,每个点有一个运算符(与.或.异或)和一个数,支持两种操作,第一种修改一个点的运算符和数,第二种给出x,y,z,询问若有一个0~z之间的数从点x走到点y(简单路径),并且对 ...

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

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

  6. [洛谷P3613]睡觉困难综合症

    写码30min,调码3h的题.. 好在最后查出来了 , , n, x, y, z); 改成了 , , n, mark[x], y, z); 然后$40\rightarrow 100$ #include ...

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

    传送门 题解 人生第一道由乃…… 做这题之前应该先去把这一题给切掉->这里 我的题解->这里 然后先膜一波zsy大佬和flashhu大佬 大体思路就是先吧全0和全1的都跑答案,然后按位贪心 ...

  8. bzoj3668: [Noi2014]起床困难综合症

    从高位到低位枚举期望的应该是ans最高位尽量取一.如果该数最高位为o的话能够取得1直接更新ans否则判断该位取1是否会爆m不会的话就加上. #include<cstdio> #includ ...

  9. bzoj千题计划238:bzoj3668: [Noi2014]起床困难综合症

    http://www.lydsy.com/JudgeOnline/problem.php?id=3668 这..一位一位的来就好了呀 #include<cstdio> #include&l ...

随机推荐

  1. Python打包分发工具setuptools

    作为Python标准的打包及分发工具,setuptools可以说相当地简单易用.它会随着Python一起安装在你的机器上.你只需写一个简短的setup.py安装文件,就可以将你的Python应用打包 ...

  2. 让linux远程主机在后台运行脚本

    后台挂起:python xxx.py & 在脚本命令后面加入"&"符号就可以后台运行.结束进程:kill -9 sidps -ef | grep ... 查询sid

  3. win10 系统右键菜单不显示文字(只有小图标)修复方法

    如下图,win10点击鼠标右键调出菜单时,看不到菜单的文字,只显示了小图标. 解决方法: Cortana 搜索 cmd ,看到 命令提示符,右键,选择 以管理员身份运行. 在命令提示符里输入以下命令, ...

  4. Python爬虫基本原理

    爬虫基本原理 1. 什么是爬虫 请求网站并提取数据的自动化程序. 2. 爬虫基本流程 发起请求 通过HTTP库向目标站点发起请求,即发送一个Request,请求可以包含额外的headers等信息,等待 ...

  5. LeetCode & Q217-Contains Duplicate-Easy

    Array Hash Table Description: Given an array of integers, find if the array contains any duplicates. ...

  6. emqtt 试用(九)ssl认证 - 客户端 mqttfx 验证

    一.代码生成证书 1.安装openssl,配置path变量 安装文件:Win64OpenSSL-1_1_0f.exe 安装openssl:C:\OpenSSL-Win64 配置path变量:C:\Op ...

  7. SpringCloud的应用发布(三)vmvare+linux,xftp,xshell连接linux失败

    Vmvare内的linux虚拟机已经启动,但是 xftp和xshell连接不上? 环境信息:子网 192.168.136.* linux ip:192.168.136.100 一.核对linux的ip ...

  8. LINGO 基础学习笔记

    LINGO 中建立的优化模型可以由5个部分组成,或称为 5 段(section): (1)集合段(SETS):这部分要以"SETS:"开始,以"ENDSETS" ...

  9. Archaius 原理

    Archaius 原理 Archaius是什么? Archaius提供了动态修改配置的值的功能,在修改配置后,不需要重启应用服务.其核心思想就是轮询配置源,每一次迭代,检测配置是否更改,有更改重新更新 ...

  10. PHP 通过fsockopen函数获取远程网页源码

    <?php $fp = fsockopen("www.baidu.com", 80, &$errno, &$errstr, 10); if(!$fp) { e ...