博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[bzoj3668][Noi2014]起床困难综合症/[洛谷3613]睡觉困难综合症
阅读量:5049 次
发布时间:2019-06-12

本文共 6796 字,大约阅读时间需要 22 分钟。

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

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

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

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

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

#include
#include
#include
#define getchar() (*S++)#define ll unsigned long long#define MN 100000#define MK 63#define pa pair
#define mp(x,y) make_pair(x,y)char B[1<<26],*S=B;using namespace std;inline ll llread(){ ll x = 0; char ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x;}inline int read(){ int x = 0; char ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x;}int L[MN*4+5],R[MN*4+5];struct node{ ll s[2][2]; ll x[2][2];}T[MN*4+5],ans,a;int op[MN+5];int n,m,z,dn=0,tp1,tp2,dfn[MN+5],top[MN+5],dep[MN+5],num[MN+5],size[MN+5],mx[MN+5],fa[MN+5],head[MN+5],cnt=0;struct edge{
int to,next;}e[MN*2+5];ll t[MN+5];pa q[MN+5],q2[MN+5];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[0][0]=(ans.s[0][1]&c.s[1][0])|(ans.s[0][0]&c.s[0][0]); a.s[0][1]=(ans.s[0][1]&c.s[1][1])|(ans.s[0][0]&c.s[0][1]); a.s[1][0]=(ans.s[1][1]&c.s[1][0])|(ans.s[1][0]&c.s[0][0]); a.s[1][1]=(ans.s[1][1]&c.s[1][1])|(ans.s[1][0]&c.s[0][1]); ans=a;}void update2(const node&c){ a.s[0][0]=(ans.s[0][1]&c.x[1][0])|(ans.s[0][0]&c.x[0][0]); a.s[0][1]=(ans.s[0][1]&c.x[1][1])|(ans.s[0][0]&c.x[0][1]); a.s[1][0]=(ans.s[1][1]&c.x[1][0])|(ans.s[1][0]&c.x[0][0]); a.s[1][1]=(ans.s[1][1]&c.x[1][1])|(ans.s[1][0]&c.x[0][1]); ans=a;}void update(int x){ int l=x<<1,r=l|1; T[x].s[0][0]=(T[l].s[0][1]&T[r].s[1][0])|(T[l].s[0][0]&T[r].s[0][0]); T[x].s[0][1]=(T[l].s[0][1]&T[r].s[1][1])|(T[l].s[0][0]&T[r].s[0][1]); T[x].s[1][0]=(T[l].s[1][1]&T[r].s[1][0])|(T[l].s[1][0]&T[r].s[0][0]); T[x].s[1][1]=(T[l].s[1][1]&T[r].s[1][1])|(T[l].s[1][0]&T[r].s[0][1]); T[x].x[0][0]=(T[r].x[0][1]&T[l].x[1][0])|(T[r].x[0][0]&T[l].x[0][0]); T[x].x[0][1]=(T[r].x[0][1]&T[l].x[1][1])|(T[r].x[0][0]&T[l].x[0][1]); T[x].x[1][0]=(T[r].x[1][1]&T[l].x[1][0])|(T[r].x[1][0]&T[l].x[0][0]); T[x].x[1][1]=(T[r].x[1][1]&T[l].x[1][1])|(T[r].x[1][0]&T[l].x[0][1]);}void init(int x,int k){ T[x].s[0][0]=T[x].s[0][1]=T[x].s[1][0]=T[x].s[1][1]=0; if(op[k]==1) for(register int i=0;i<=MK;i++) T[x].s[0][0]|=1LLU<
<
0]|=1LLU<
0]|=1LLU<
0) T[x].s[0][1]|=(1LLU<
<
>1; build(x<<1,l,mid);build(x<<1|1,mid+1,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]>>1; if(k<=mid) renew(x<<1,k); else renew(x<<1|1,k); update(x);}void dfs1(int x,int f){ fa[x]=f;size[x]=1;mx[x]=0; for(int i=head[x];i;i=e[i].next) if(e[i].to!=f) { dep[e[i].to]=dep[x]+1; 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]>>1; if(r<=mid) query(x<<1,l,r); else if(l>mid) query(x<<1|1,l,r); else query(x<<1,l,mid),query(x<<1|1,mid+1,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]>>1; if(r<=mid) query2(x<<1,l,r); else if(l>mid) query2(x<<1|1,l,r); else query2(x<<1|1,mid+1,r),query2(x<<1,l,mid);}void solve(int x,int y,ll t){ tp1=tp2=0; ans.s[0][0]=ans.s[1][1]=-1; ans.s[0][1]=ans.s[1][0]=0; 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=1;i<=tp1;i++) query2(1,q[i].first,q[i].second); if(dfn[x]>dfn[y]) query2(1,dfn[y],dfn[x]); else query(1,dfn[x],dfn[y]); for(int i=tp2;i;i--) query(1,q2[i].first,q2[i].second); ll sum=0; for(register int i=MK;i>=0;i--) { ll th=(1LLU<

 

转载于:https://www.cnblogs.com/FallDream/p/bzoj3668.html

你可能感兴趣的文章
一个Java程序员应该掌握的10项技能
查看>>
c#英文大小写快捷键
查看>>
tpframe免费开源框架又一重大更新
查看>>
什么是架构设计
查看>>
程序员学习能力提升三要素
查看>>
PHP 微信错误状态返回码说明
查看>>
【4.1】Python中的序列分类
查看>>
ubuntu 移动文件
查看>>
Easy Mock
查看>>
看看 Delphi XE2 为 VCL 提供的 14 种样式
查看>>
Python内置函数(29)——help
查看>>
机器学习系列-tensorflow-01-急切执行API
查看>>
《架构之美》阅读笔记05
查看>>
《大道至简》读后感——论沟通的重要性
查看>>
JDBC基础篇(MYSQL)——使用statement执行DQL语句(select)
查看>>
java中Hashtable和HashMap的区别(转)
查看>>
关闭数据库
查看>>
webStrom智能提示忽略首字母大小写问题
查看>>
层叠加的五条叠加法则(一)
查看>>
设计模式六大原则(5):迪米特法则
查看>>