来自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 = 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<MK+1> 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<<i))>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<<i))>0][i]=1; }elsefor(int i=0;i<=MK;i++)if(t[T[x].l]&(1<<i))T[x].s[0][1][i]=T[x].s[1][0][i]=1;elseT[x].s[0][0][i]=T[x].s[1][1][i]=1;return;}int mid=l+r>>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<<i)<=m&&T[1].s[1][1][i]&&!T[1].s[0][1][i])  ans+=1<<i,m-=1<<i;else if(T[1].s[0][1][i]) ans+=1<<i;}printf("%d\n",ans);return 0;
}

洛谷那道题是它的强化版,首先变成了一棵树,每个节点都有一个符号和数字,支持修改,查询路径,数字<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[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<<i,T[x].s[1][(t[k]&(1LLU<<i))>0]|=1LLU<<i;else if(op[k]==2)for(register int i=0;i<=MK;i++)T[x].s[1][1]|=1LLU<<i,T[x].s[0][(t[k]&(1LLU<<i))>0]|=1LLU<<i;elsefor(register int i=0;i<=MK;i++)if((t[k]&(1LLU<<i))>0)T[x].s[0][1]|=(1LLU<<i),T[x].s[1][0]|=(1LLU<<i);elseT[x].s[0][0]|=(1LLU<<i),T[x].s[1][1]|=(1LLU<<i);        T[x].x[0][0]=T[x].s[0][0];T[x].x[0][1]=T[x].s[0][1];T[x].x[1][0]=T[x].s[1][0];T[x].x[1][1]=T[x].s[1][1];
}void build(int x,int l,int r)
{if((L[x]=l)==(R[x]=r)) {init(x,num[l]);return;}int mid=l+r>>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<<i);if(th<=t&&(ans.s[1][1]&(1LLU<<i))&&!(ans.s[0][1]&(1LLU<<i)))  sum+=th,t-=th;else if(ans.s[0][1]&(1LLU<<i)) sum+=th;}printf("%llu\n",sum);
}int main()
{fread(B,1,1<<26,stdin);n=read();m=read();z=read();for(register int i=1;i<=n;i++)op[i]=read(),t[i]=llread();for(register int i=1;i<n;i++) {register int u=read(),v=read();ins(u,v);}dfs1(1,0);dfs2(1,1);build(1,1,n);for(register int i=1;i<=m;i++){int opt=read(),x=read(),y=read();ll z=llread();if(opt==1) solve(x,y,z);else {op[x]=y;t[x]=z;renew(1,dfn[x]);}}return 0;
}

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

[bzoj3668][Noi2014]起床困难综合症/[洛谷3613]睡觉困难综合症相关推荐

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

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

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

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

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

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

  4. [BZOJ3668][Noi2014]起床困难综合症 贪心

    3668: [Noi2014]起床困难综合症 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 2409  Solved: 1360 [Submit][ ...

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

    3668: [Noi2014]起床困难综合症 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 2547  Solved: 1460 [Submit][ ...

  6. BZOJ3668:[NOI2014]起床困难综合症(贪心)

    Description 21 世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳.作为一名青春阳光好少年,atm 一直坚持与起床困难综合症作斗争.通过研究相关文献,他找 ...

  7. BZOJ3668[NOI2014] 起床困难综合症

    原题链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3668 起床困难综合症 Description 21 世纪,许多人得了一种奇怪的病:起床困 ...

  8. 【题解】洛谷P2114 [NOI2014]起床困难综合症

    前往:我自己搭建的博客 题目 洛谷P2114 [NOI2014]起床困难综合症 题解 题意简化为:在0~m之间找一个数,使得这个数在一系列操作后最大. 由于原数有大小限制,又要使得到的数尽量大,为了充 ...

  9. 洛谷 P2114 [NOI2014]起床困难综合症 解题报告

    P2114 [NOI2014]起床困难综合症 题目描述 21世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳.作为一名青春阳光好少年,atm一直坚持与起床困难综合症作 ...

  10. 洛谷P2114 [NOI2014]起床困难综合症

    P2114 [NOI2014]起床困难综合症 题目描述 21世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳.作为一名青春阳光好少年,atm一直坚持与起床困难综合症作 ...

最新文章

  1. ENJOYLink欢联,以独创技术满足数据中心布线
  2. 查看Linux服务器下的内存使用情况
  3. 实验十 配置EIGRP协议
  4. 线性表的链式表示——循环链表
  5. linux 系统打造man中文帮助手册图解
  6. Stanford Machine Learning
  7. 零基础学Python(第十四章 字典)
  8. muck数据的概念理解
  9. linux主备网卡切换脚本,Keepalived主备切换时执行脚本
  10. DQL 学习4-- Using DQL
  11. 使用python写机器学习算法遇到的问题
  12. 常用软件版本查看Windows下
  13. Win10 CMD命令大全
  14. 回车键为什么叫做回车键?
  15. Nacos下载与安装
  16. 三极管原理及贴片封装注意
  17. 【2022网易雷火】游戏研发笔试-AC代码及题目分享
  18. IDEA之Windows快捷键
  19. python--身体质量指数BMI
  20. 黑客入门教程(非常详细)从零基础入门到精通,看完这一篇就够了

热门文章

  1. matlab bar 填充花纹,科学网—使用matlab绘画柱状图,且使用不同的图案填充 - 时杰的博文...
  2. 测试nb信号的软件_NB频点概述
  3. latex 公式去掉不要编号
  4. linux系统c语言编译icpc,ACM-ICPC 比赛环境的使用
  5. mysql 为什么性能不稳定_浅谈MySQL 数据库性能优化
  6. alians mysql_Linux学习——Shell基础
  7. 简述旋转编码器的工作原理_绝对值编码器工作原理以及故障处理方法有哪些?...
  8. 1.5.PHP7.1 狐教程-(PHP开发工具 PHPStorm 配置)
  9. ubuntu 17.x/CentOS 7.x中安装JAVA JDK
  10. Spring JdbcTemplate 模板剖析 之 常用 增删改查