考试的一道附加题~

一看题目描述:把区间[l,r]里每个数异或上x,求区间[l,r]里所有数的异或和,这明显的要用数据结构或RMQ吧。

恩,所以正解就是线段树啦,至于树状数组行与否,不知道~

water_lift:这不是sb题嘛?线段树板子题都不会?把加法操作改成异或操作不就好啦?

其实好像真的是这样的,将加法操作改成了乘法操作;

然后你会发现自己只得了20分的暴力分,没错!相当于没写线段树!

因为线段树区间修改需要用到一个非常重要的东西:

懒标记

为什么要用到这个,直接暴力递归不好吗?

问得好!

假设我们每进行一次加法或减法操作我们就要从根节点一直递归到它儿子再递归回来,这样做好像没什么问题,但是,太耗时!

我们不如将这个区间内的所有元素做上一个懒标记!(顾名思义,懒标记很懒嘛,查到它它才改,不查就不改!真是壮士!)

这个懒标记是干嘛滴呢?假设我们对一个区间进行了n次操作,每次操作都给这个区间加上Ai(i从1~n),不做懒标记的话我们就要递归n次,树一大节点一多直接T得飞起!

所以我们就给这个区间的元素做上懒标记,每次懒标记加上要加上的Ai的值,但是不往下递归,所以到n次操作后这个区间的元素的懒标记就是:A1+A2+A3……+An,这样我们一次递归加上懒标记就好啦。

举个例子:

sum是这个区间内的总和相对于初始化增加了多少,inc是这个区间的每个元素相对于初始化增加了多少。

然后我们可以进行第一步操作:让[2,7]的每个元素增加2

在全部的大区间[1,9]内,由于1~7都在这个区间内,所以总和相对于一开始的是增加了2*7=14,所以sum的值为14;但是[1,9]又不完全被包含在[1,7]内,所以我们不能更新inc值(看inc的定义,8和9不能+2)

因为区间[1,9]内还有元素不用+2,所以我们要继续往下找:

我们找到了区间[1,5]和区间[6,9],我们发现:区间[1,5]全部都在[1,7]内,所以区间[1,5]的inc值就可以更新为2了,sum值就是5*2=10;但是区间[6,9]还有元素不在区间[1,7]的范围内所以我们将这个区间继续往下找,同时将这个区间的sum值更新为4;

[6,9]可以分成[6,7]和[8,9],我们发现:区间[6,7]全部都在[1,7]以内,所以将区间[6,7]的inc值更新为2,sum值为2*2=4。到这步我们就发现[1,7]以内已经全部被找过了,所以我们就找完了!

接下来我们查询[1,6]的和:

还是按照原来的思路:从根节点开始找,发现[1,9]并不完全被包含在所查区间内,所以我们就去找它的儿子;

我们找到了[1,5],发现并不完全被包含在[2,6]内,所以我们继续往下找,并将inc值传给它的两个儿子;找到了[1,3]和[4,5],我们发现区间[4,5]全部被包含在内了,所以我们直接返回sum值+原区间和就好啦,sum=inc*len(区间长度)=2*2=4,但是[1,3]并不完全被包含在内,所以我们将[1,3]的inc值传给它的儿子,并继续往下找:

我们找到了[1,2]和区间[3,3](就是3),我们发现3完全被包含在所查区间内了,所以我们直接返回sum值+原区间和就好啦,sum=inc*len(区间长度)=2*1=2;但是区间[1,2]并不完全被包含在内,所以继续从它的儿子里面找,并将inc值传给儿子:

我们找到了1和2,1不在所查区间内就不管它了(不清楚懒标记inc值),我们发现2在所查区间内,所以直接返回sum值+原区间和就好啦,sum的公式就不用说了...

到这里的话,大家应该都会懒标记了QwQ~,毕竟前面讲的辣么详细。

但是还是会TLE几个点,我们继续找原因!

我们看到题目中给出的提示,它有什么用呢?

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,cz,x,y,k;
int sum[],a[],lazy[]; //注意开4倍空间比较保险 void init(int node,int x,int y) //预处理一下
{
if(x==y) sum[node]=a[x]; //叶子结点,直接赋值
else
{
int mid=(x+y)>>;
init(node*,x,mid); //找左儿子
init(node*+,mid+,y); //找右儿子
sum[node]=sum[node*]^sum[node*+]; //更新父亲结点
}
lazy[node]=;
}
void pushdown(int node,int l,int r) //标记下传过程
{
int mid=(l+r)>>;
lazy[node*]^=lazy[node]; //下传给左儿子
lazy[node*+]^=lazy[node]; //下传给右儿子
sum[node*]^=lazy[node]*((mid-l+)%); //更新左儿子的sum,用到了上面讲的优化2:更新奇数次就是更新一次,更新偶数次就是没更新
sum[node*+]^=lazy[node]*((r-mid)%);
lazy[node]=; //注意清空,这里不是标记永久化
}
void add(int node,int l,int r,int x,int y,int k) //区间[x,y]的每个数都异或上k
{
if(l>=x&&r<=y) //当前分解的区间[l,r]被完全包含在[x,y]里的话,直接更新
{
sum[node]^=k*((r-l+)%); //优化2
lazy[node]^=k; //更新懒标记
return ;
}
pushdown(node,l,r); //先要标记下传
int mid=(l+r)>>;
if(x<=mid) add(node*,l,mid,x,y,k); //与左区间有交集就去找左区间
if(y>=mid+) add(node*+,mid+,r,x,y,k); //与右区间有交集就去找右区间
sum[node]=sum[node*]^sum[node*+]; //再更新父亲结点的sum
}
int ask(int node,int l,int r,int x,int y) //询问区间[x,y]内的异或和
{
if(l>=x&&r<=y) return sum[node]; //被[x,y]包含的话就直接返回
pushdown(node,l,r);
int res=,mid=(l+r)>>;
if(x<=mid) res^=ask(node*,l,mid,x,y); //与左区间有交集就去找左区间
if(y>=mid+) res^=ask(node*+,mid+,r,x,y); //与右区间有交集就去找右区间
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
init(,,n);
for(int i=;i<=m;i++)
{
scanf("%d%d%d",&cz,&x,&y);
if(cz==)
{
scanf("%d",&k); //[x,y]异或上k
add(,,n,x,y,k);
}
else printf("%d\n",ask(,,n,x,y)); //询问[x,y]的异或和
}
return ;
}

2019.6.28 校内测试 T4 【音乐会】达拉崩吧·上的更多相关文章

  1. T83312 【音乐会】达拉崩吧·上

    T83312 [音乐会]达拉崩吧·上 题解 线段树板子题 把原来的 + 变成 ^ 但是注意一下懒标记,这里讲一下小技巧 代码 #include<bits/stdc++.h> using n ...

  2. 2019.6.28 校内测试 T3 【音乐会】道路千万条

    大眼一看最下面的题意解释的话,发现这和洛谷P1310表达式的值挺像的,大概都是给定一些运算符号,让最后的表达式为true的概率,为false的概率啥的QwQ~: 然后这个题嘛?就是在所有的运算符中提溜 ...

  3. 2019.6.28 校内测试 T2 【音乐会】二重变革

    看到这个题之后,一个很暴力很直接的想法就是贴上题目中的代码然后交上去走人,但是很显然这是会TLE+MLE的,想想谁会这么傻把主要代码给你QwQ~: 其实这段代码是想告诉你一件事:用序列中的大数减去小数 ...

  4. 2019.6.28 校内测试 T1 Jelly的难题1

    这题面有点难理解,建议直接跳到题意解释那一部分(虽然我觉得解释的不大对,但按照解释来做确实能AC): 按照“题意解释”的思路来思考这个题,那么就十分的简单了: 1.首先要读入这个字符矩阵,可以用cin ...

  5. 2019.7.9 校内测试 T3 15数码问题

    这一次是交流测试?边交流边测试(滑稽 15数码问题 大家应该都玩过这个15数码的游戏吧,就在桌面小具库那里面哦. 一看到这个题就知道要GG,本着能骗点分的原则输出了 t 个无解,本来以为要爆零,没想到 ...

  6. 2019.7.9 校内测试 T2 极值问题

    这一次是交流测试?边交流边测试(滑稽 极值问题 乍一看这是一道数学题,因为1e9的数据让我暴力的心退却. 数学又不好,不会化简式子嘞,咋办? 不怕,咱会打表找规律.(考场上真的是打表找出了规律,打表打 ...

  7. 2019.7.9 校内测试 T1挖地雷

    这一次是交流测试?边交流边测试(滑稽 挖地雷 这个题是一个递推问题. 首先我们看第一个格子,因为它只影响了它的上面和右上面这两个地方是否有雷. 我们可以分3种情况讨论: 1. 第一个格子的数字是2: ...

  8. 【8.28校内测试】【区间DP】

    感受到了生活的艰辛QAQ...这才是真正的爆锤啊...(因为t1t3还没有理解所以只能贴t2叻QAQ 区间DP...爆哭把题理解错了,以为随着拿的东西越来越多,断点也会越来越多,出现可以选很多的情况Q ...

  9. 2019.6.24 校内测试 NOIP模拟 Day 2 分析+题解

    看到Day 2的题真的想打死zay了,忒难了QwQ~ T1 江城唱晚 这明显是个求方案数的计数问题,一般的套路是DP和组合数学. 正如题目中所说,这个题是一个 math 题.      ----zay ...

随机推荐

  1. 14-MySQL DBA笔记-运维技巧和常见问题处理

    第14章 运维技巧和常见问题处理 DBA的成长,离不开对各种问题的处理.本章将为读者介绍一些运维技巧和常见问题的处理方法.我们需要意识到,别人的经验代替不了自己的经验,所以,多实践.多处理问题,最终会 ...

  2. (九)springmvc之json的处理(服务端发送json数据到客户端)

    一.json处理方法有两种 1:导入Spring需要json的jar包.(本例使用) 使用@ResponseBody该注解用于将Controller的方法返回的对象,通过HttpMessageConv ...

  3. tiny-Spring【2】逐步step分析-新加入特性

    tiny-Spring是黄亿华大佬自己写的一个集合IOC和AOP于一身的一种轻量级[教学用]Spring框架,它的github库地址为:https://github.com/code4craft/ti ...

  4. C# 延迟初始化 Lazy<T>

    概念:延时初始化重点是延时,用时加载,意思是对象在使用的时候创建而不是在实例化的的时候才创建.   延时加载主要应用的场景: 数据层(ADO.NET或Entity Framework等ORM,Java ...

  5. Abp 添加权限项<一>

    1.下载代码,数据库迁移,npm install 2.添加权限项: public static class PermissionNames { public const string Pages_Te ...

  6. ThinkPad T420i 上 Ubuntu 12.04 实现指纹识别登录

    ThinkPad T420i 上 Ubuntu 12.04 实现指纹识别登录 # add ppa add-apt-repository ppa:fingerprint/fprint # update ...

  7. Python练习_初识函数_day9

    1. 1.作业 1,写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者. 2,写函数,判断用户传入的对象(字符串.列表.元组)长度是否大于5. 3,写函数,检查 ...

  8. SAP官方发布的ABAP编程规范

    最近有朋友在公众号后台给我留言,"Jerry啊,你最近写的都是一些SAP研究院里面用到的新技术,能不能写点SAP传统的开发技术比如ABAP相关的东西"? 其实Jerry在刚开始写这 ...

  9. XML文件解析之DOM4J解析

    1.DOM4J介绍 dom4j的官网是http://www.dom4j.org/dom4j-1.6.1/,最新的版本是1.6.1,根据官网介绍可知.dom4j是一个易用的.开源的库,应用于Java平台 ...

  10. CentOS 安装hping3工具及安装遇到的错误及解决方法

    hping是用于生成和解析TCPIP协议数据包的开源工具.创作者是Salvatore Sanfilippo.目前最新版是hping3,支持使用tcl脚本自动化地调用其API.hping是安全审计.防火 ...