题目

描述

题目大意

维护一个序列,支持三种操作:

1、修改一段区间,将这段区间内的所有数都andandand一个数。

2、询问区间和。

3、询问区间两两相加的平方和。

N≤10000N\leq 10000N≤10000


思路

显然是一道数据结构题。

毋庸置疑的,这绝对是一棵线段树。

第三个操作还是比较简单的:

∑(ai+aj)2=∑ai2+aj2+2aiaj=2∗len∗∑ai2+2∑aiaj=2∗len∗∑ai2+2(∑ai)2\sum{(a_i+a_j)^2} \\
=\sum{a_i^2+a_j^2+2a_ia_j}\\
=2*len*\sum{a_i^2}+2\sum{a_ia_j}\\
=2*len*\sum{a_i^2}+2\left(\sum{a_i}\right)^2∑(ai​+aj​)2=∑ai2​+aj2​+2ai​aj​=2∗len∗∑ai2​+2∑ai​aj​=2∗len∗∑ai2​+2(∑ai​)2

所以只需要维护区间和还有区间平方和。

这题中,最讨厌的就是修改操作,好端端的,干嘛要来个位运算!

所以我就是着将所有的位分开来。

然而,搞不了第三个询问……

想了半天后弃疗看题解。


正解

这题正解就是直接暴力,没错,就是暴力。

对于线段树的每一个节点,维护一个值表示这段区间内或起来的和。

在修改的时候,我们就可以通过这个东西来判断这个区间里面是否有需要修改的数。

如果有,就继续往下,将它揪出来,暴力修改。

然后?然后就没了啊……

听起来这个方法的时间很诡异,实际上——

对于NNN个点,每个点一共有303030个位,又因为修改过一个位之后就再也不可能修改这个位,所以,顶多修改30N30N30N次。

乘上线段树的高度就是30Nlg⁡N30N\lg N30NlgN次。

所以时间复杂度是O(Nlg⁡Nlg⁡109)O(N\lg N\lg 10^9)O(NlgNlg109)


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100000
#define BIt 30
#define mo 998244353
inline long long pow2(long long x){return x*x;}
int n;
int a[N+1];
struct Ret{//分别是区间和、区间平方和
long long sum;
int sum2;
};
struct Node{
int o;//表示or值
Ret s;
} d[N*4+1];
void init(int,int,int);
void find(int,int,int,int,int,int);//找被修改区间完全覆盖的点
void change(int,int,int,int);
inline Ret operator+(const Ret &a,const Ret &b){
return {a.sum+b.sum,(a.sum2+b.sum2)%mo};
}
Ret query(int,int,int,int,int);
int main(){
freopen("seg.in","r",stdin);
freopen("seg.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;++i)
scanf("%d",&a[i]);
init(1,1,n);
int T;
scanf("%d",&T);
while (T--){
int op;
scanf("%d",&op);
if (op==1){
int l,r,x;
scanf("%d%d%d",&l,&r,&x);
find(1,1,n,l,r,x);
}
else if (op==2){
int l,r;
scanf("%d%d",&l,&r);
printf("%lld\n",query(1,1,n,l,r).sum);
}
else{
int l,r;
scanf("%d%d",&l,&r);
Ret res=query(1,1,n,l,r);
printf("%lld\n",(((long long)res.sum2*(r-l+1)%mo+pow2(res.sum%mo)%mo)<<1)%mo);
}
}
return 0;
}
void init(int k,int l,int r){
if (l==r){
d[k].s.sum=d[k].o=a[l];
d[k].s.sum2=(long long)a[l]*a[l]%mo;
return;
}
int mid=l+r>>1;
init(k<<1,l,mid);
init(k<<1|1,mid+1,r);
d[k].o=d[k<<1].o|d[k<<1|1].o;
d[k].s=d[k<<1].s+d[k<<1|1].s;
}
void find(int k,int l,int r,int st,int en,int x){
if (st<=l && r<=en){
change(k,l,r,x);
return;
}
int mid=l+r>>1;
if (st<=mid)
find(k<<1,l,mid,st,en,x);
if (mid<en)
find(k<<1|1,mid+1,r,st,en,x);
d[k].o=d[k<<1].o|d[k<<1|1].o;
d[k].s=d[k<<1].s+d[k<<1|1].s;
}
void change(int k,int l,int r,int x){
if ((d[k].o&x)==d[k].o)
return;
if (l==r){
d[k].s.sum=d[k].o&=x;
d[k].s.sum2=(long long)d[k].o*d[k].o%mo;
return;
}
int mid=l+r>>1;
change(k<<1,l,mid,x);
change(k<<1|1,mid+1,r,x);
d[k].o=d[k<<1].o|d[k<<1|1].o;
d[k].s=d[k<<1].s+d[k<<1|1].s;
}
Ret query(int k,int l,int r,int st,int en){
if (st<=l && r<=en)
return d[k].s;
int mid=l+r>>1;
Ret res={0,0};
if (st<=mid)
res=res+query(k<<1,l,mid,st,en);
if (mid<en)
res=res+query(k<<1|1,mid+1,r,st,en);
return res;
}

总结

数据结构的时间复杂度,不应该只看他每次操作的复杂度,还要看看总共最多的复杂度。尤其是类似一次性修改的东西(就是这个数据修改过一次之后就不能再修改了)。

话说,我突然想起以前的一道题目:

有一道数据结构提,正解是分块的根号做法,题解说,线段树不能做……

我坚持用线段树,最终AC了那题,log做法,吊打标算。风光了一时

当时用的也差不多是这样的思想……

【NOIP2018模拟11.01】树的更多相关文章

  1. 【NOIP2019模拟11.01】Game(贪心+线段树)

    Description: ​ 小 A 和小 B 在玩一个游戏,他们两个人每人有

  2. [jzoj NOIP2018模拟11.02]

    嗯T1忘记取模了,100到20 嗯T2忘记了那啥定理,暴力也写炸了,这题我认 嗯T3线段树合并分裂没有写炸,考场上就知道妥妥的70分.但是,分数出的时候听到有人说暴力也是70分,我???脸黑,枉我敲了 ...

  3. 6402. 【NOIP2019模拟11.01】Cover(启发式合并)

    题目描述 Description 小 A 现在想用

  4. 17.10.31&11.01

    10.31模拟考试 Prob.1(AC)裸的矩阵幂 Prob.2(WA)(类似括号匹配求合法方案数) 卡特兰数的一个模型运用.可以推出一个式子(推导方法一个erge讲的,一个骚猪讲的) Prob.3( ...

  5. 8.1 NOIP模拟11

    8.1 NOIP模拟 11 今天上午返校之后,颓了一会,然后下午就开始考试,中午睡着了,然后刚开始考试的时候就困的一匹,我一看T1,woc,这不是之前线段树专题的题啊,和那道题差不多,所以我..... ...

  6. [NOIP2018模拟赛10.16]手残报告

    [NOIP2018模拟赛10.16]手残报告 闲扯 炉石乱斗模式美滋滋啊,又颓到好晚... 上来T2先敲了树剖,看T1发现是个思博DP,然后没过大样例,写个暴力发现还是没过大样例!?才发现理解错题意了 ...

  7. JZOJ 4298. 【NOIP2015模拟11.2晚】我的天

    4298. [NOIP2015模拟11.2晚]我的天 (File IO): input:ohmygod.in output:ohmygod.out Time Limits: 1000 ms Memor ...

  8. JZOJ 3929. 【NOIP2014模拟11.6】创世纪

    3929. [NOIP2014模拟11.6]创世纪 (Standard IO) Time Limits: 1000 ms Memory Limits: 65536 KB Description 上帝手 ...

  9. 【NOIP2015模拟11.5】JZOJ8月5日提高组T2 Lucas的数列

    [NOIP2015模拟11.5]JZOJ8月5日提高组T2 Lucas的数列 题目 PS:\(n*n*T*T<=10^{18}\)而不是\(10^1*8\) 题解 题意: 给出\(n\)个元素的 ...

随机推荐

  1. 十二. for of 示例 (可以解决大多数应用场景)

    for of entries() 可以同时拿到数组的索引跟值 因此可以使用解构的语法: for of 示例 1. 求和 2.字符串

  2. mysql 的特殊函数

    1. FORMAT() 函数 函数用于对字段的显示进行格式化 语法: SELECT FORMAT(column_name,format) FROM table_name column_name  必需 ...

  3. csps-模拟7980题解

    题面:https://www.cnblogs.com/Juve/articles/11712702.html 树: 我太sb了不知道DROT是1,还在sb找根 记录一个fa[]数组,表示x的祖先中第一 ...

  4. (转)Android开发把项目打包成apk

    转:http://blog.csdn.net/luoyin22/article/details/7862742 做完一个Android项目之后,如何才能把项目发布到Internet上供别人使用呢?我们 ...

  5. 10 行 Python 代码实现模糊查询/智能提示

    10 行 Python 代码实现模糊查询/智能提示   1.导语: 模糊匹配可以算是现代编辑器(如 Eclipse 等各种 IDE)的一个必备特性了,它所做的就是根据用户输入的部分内容,猜测用户想要的 ...

  6. PPM 信号解析

    PWM信号 PWM信号用于控制单个电调或者单个舵机脉冲宽度调制信号. 像华科尔DEVO 10遥控接收器(RX1002)就输出10路PWM,参看下图. 舵机(电调)上用到PWM信号种类很多,我们这里对常 ...

  7. POJ 3449 /// 判断线段相交

    题目大意: 给出多个多边形及其编号 按编号顺序输出每个多边形与其相交的其他多边形编号 注意一个两个多个的不同输出 将每个多边形处理成多条边 然后去判断与其他多边形的边是否相交 计算正方形另外两点的方法 ...

  8. 在使用python语言的open函数时,提示错误OSError: [Errno 22] Invalid argument: ‘文件路径’

    如题,在使用python语言的open函数时,提示错误OSError: [Errno 22] Invalid argument: '文件路径',在查阅了大量资料后也得到了一些解决方案,但是这些解决方案 ...

  9. Eclipse 中安装 CDT 插件编写 C/C++

    使用到的软件 1.Eclipse 开发工具 2.MinGW 编译器 一.Eclipse 中安装 CDT 插件 打开 Eclipse 插件市场 搜索 CDT,并找到如下的插件.插件的版本名字可能不太一样 ...

  10. Python3基础笔记_字典

    # Python3 字典 dict = {'} # 1.访问字典里的值 ,字典中没有key会报错 # 2.修改字典 print("修改之前:", dict['Beth']) dic ...