题目

描述

题目大意

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

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. Windows del

    删除一个或数个文件. DEL [/P] [/F] [/S] [/Q] [/A[[:]attributes]] namesERASE [/P] [/F] [/S] [/Q] [/A[[:]attribu ...

  2. JavaScript的函数进阶

    函数进阶 1立即执行函数表达式 立即执行的函数表达式的英文全称为Immediately Invoked Function Expression,简称就为IIFE.这是一个如它名字所示的那样,在定义后就 ...

  3. HDU-2095-find your present (2)-位或/STL(set)

    In the new year party, everybody will get a "special present".Now it's your turn to get yo ...

  4. threading线程例子 (27-08)

    利用阻塞的时间空闲去执行另一个子线程 import threading from time import ctime, sleep def music(func): for i in range(2) ...

  5. <Python基础>列表的基本操作

    s = 'abCDeFg aBcDea' s1 = s.split('D',3) #以s1列表为例 print(s1) #增 s1.append('foxabc') #返回值None,直接增到列表的最 ...

  6. Mybatis Resultmap 简化之超级父类

    我们在写 mybatis多表关联查询的时候 ,要配置  resultmap ,实在太麻烦.而这个超级父类 可以省去我们查询多表时的map public class SuperPojo extends ...

  7. jmeter-测试https请求

    找了一个HTTPS请求的网站尝试. 我用的是chrome,点这个小锁(如果是IE也可以在网页上右键,属性,高级,证书) 或 看到下图,点击“复制到文件” 或 把导出的证书打成.store 用此命令进行 ...

  8. TortoiseGit可能遇到Permission denied (publickey).

    1.检测是不是没设置公钥和私钥 2.公钥有没有添加到git账户里面去 3.检测如下图路径正确不正确

  9. 《代码整洁之道》ch1~ch4读书笔记 PB16110698 (~3.8 第一周)

    <代码整洁之道>ch1~ch4读书笔记  <clean code>正如其书名所言,是一本关于整洁代码规范的“教科书”.作者在书中通过实例阐述了整洁代码带来的种种利处以及混乱代码 ...

  10. Luogu P2619 [国家集训队2]Tree I(WQS二分+最小生成树)

    P2619 [国家集训队2]Tree I 题意 题目描述 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有\(need\)条白色边的生成树. 题目保证有解. 输入输出格式 输入格式 ...