考试的一道附加题~

一看题目描述:把区间[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. PHP trait介绍

    Trait 自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait. Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制.Trait 为了减少单继承语言的限制, ...

  2. (二)发布第一个WebService服务与DSWL文档解析

    1. 编写接口 package service; import javax.jws.WebService; /** * 第一个webservice服务, * @WebService注解表示这是一个we ...

  3. 获取类的描述信息 DescriptionAttribute

    static void Main(string[] args) { var attrs = typeof(TestClass).GetCustomAttributes(typeof(System.Co ...

  4. Q-Dir

    Q-dir,可以分界面,分文件夹,快捷选择等优势,非常好用的工具,可以替代微软的File Explorer. 官网:https://www.softwareok.com/?seite=Freeware ...

  5. js之split拆分字符串

    js之split拆分字符串 1.单字符拆分 let arr = str.split(',') 2.多字符拆分 let arr = str.split(/[(),]/)

  6. 结对编程作业(python实现)

    一.Github项目地址:https://github.com/asswecanfat/git_place/tree/master/oper_make 二.PSP2.1表格: PSP2.1 Perso ...

  7. 第二章 Django之python安装(1)

    Python 安装 Django 由百分百的纯 Python 代码编写而成,因此必须在系统中安装 Python .Django 需要 2.3 或更高版本的 Python.如果使用的是 Linux 或 ...

  8. Image Processing and Analysis_15_Image Registration:a survey of image registration techniques——1992

    此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...

  9. 【Day5】3.反爬策略之模拟登录

    import urllib.request as ur import user_agent import lxml.etree as le request = ur.Request( url='htt ...

  10. 【问题】This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.

    转载请注明出处:https://www.cnblogs.com/kelamoyujuzhen/p/9087725.html  这类问题归根到底就是软件源问题,Linux下安装软件不像windows.L ...