前言

这次的题思维上倒不是很难,就是代码量比较大。

一、开关

洛谷的这种板子题写起来比cf顺多了()

#include <bits/stdc++.h>
using namespace std;typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll>pll;const int MAXN=1e5+5;//开着的灯数
vector<int>cnts(MAXN<<2);
//懒信息 -> 是否反转
vector<bool>info(MAXN<<2);//懒更新
void lazy(int i,int n)
{cnts[i]=n-cnts[i];info[i]=!info[i];
}//下发
void down(int i,int ln,int rn)
{if(info[i]){lazy(i<<1,ln);lazy(i<<1|1,rn);info[i]=false;}
}//汇总
void up(int i)
{cnts[i]=cnts[i<<1]+cnts[i<<1|1];
}void build(int l,int r,int i)
{if(l==r){cnts[i]=0;}else{int m=(l+r)>>1;build(l,m,i<<1);build(m+1,r,i<<1|1);up(i);}info[i]=false;
}//范围反转
void reverse(int jobl,int jobr,int l,int r,int i)
{if(jobl<=l&&r<=jobr){lazy(i,r-l+1);}else{int m=(l+r)>>1;down(i,m-l+1,r-m);if(jobl<=m){reverse(jobl,jobr,l,m,i<<1);}if(m+1<=jobr){reverse(jobl,jobr,m+1,r,i<<1|1);}up(i);}
}//范围查询
int query(int jobl,int jobr,int l,int r,int i)
{if(jobl<=l&&r<=jobr){return cnts[i];}int m=(l+r)>>1;down(i,m-l+1,r-m);int ans=0;if(jobl<=m){ans+=query(jobl,jobr,l,m,i<<1);}if(m+1<=jobr){ans+=query(jobl,jobr,m+1,r,i<<1|1);}return ans;
}void solve()
{int n,m;cin>>n>>m;build(1,n,1);int l,r;int type;while(m--){cin>>type>>l>>r;if(type==0){reverse(l,r,1,n,1);}else{cout<<query(l,r,1,n,1)<<endl;}}
}int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;//cin>>t;while(t--){solve();    }return 0;
}

这个题的思路其实就很好想了,如果用1代表开,0代表关,那么范围内开着的灯的数量其实就可以表示为范围内的累加和。而对于改变灯的状态的这个操作,那么每次只需要将范围内的累加和更新为范围上的总数减去之前的累加和即可。所以代码只需要对懒更新的函数lazy稍微修改一下即可。

二、贪婪大陆

#include <bits/stdc++.h>
using namespace std;typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll>pll;const int MAXN=1e5+5;//维护范围内放地雷的开头个数和结尾个数
//如果要求查询[l,r]上的地雷种数
//就是[1,r]范围上的开头个数减去[1,l-1]上的结尾个数//放地雷的开头位置的个数
int bg[MAXN<<2];
//放地雷的结尾位置的个数
int ed[MAXN<<2];//汇总
void up(int i)
{bg[i]=bg[i<<1]+bg[i<<1|1];ed[i]=ed[i<<1]+ed[i<<1|1];
}void build(int l,int r,int i)
{if(l<r){int m=(l+r)>>1;build(l,m,i<<1);build(m+1,r,i<<1|1);up(i);}bg[i]=0;ed[i]=0;
}//范围放置
//jobt==0:在添加开头
//jobt==1:在添加结尾
void put(int jobt,int jobi,int l,int r,int i)
{if(l==r){if(jobt==0){bg[i]++;}else{ed[i]++;}}else{int m=(l+r)>>1;if(jobi<=m){put(jobt,jobi,l,m,i<<1);}else{put(jobt,jobi,m+1,r,i<<1|1);}up(i);}}//范围查询
int query(int jobt,int jobl,int jobr,int l,int r,int i)
{if(jobl<=l&&r<=jobr){return jobt==0?bg[i]:ed[i];}int m=(l+r)>>1;int ans=0;if(jobl<=m){ans+=query(jobt,jobl,jobr,l,m,i<<1);}if(m+1<=jobr){ans+=query(jobt,jobl,jobr,m+1,r,i<<1|1);}return ans;
}void solve()
{int n,m;cin>>n>>m;build(1,n,1);int q,l,r;while(m--){cin>>q>>l>>r;if(q==1){put(0,l,1,n,1);put(1,r,1,n,1);}else{int b=query(0,1,r,1,n,1);//等于1的话就没左侧了int e=l==1?0:query(1,1,l-1,1,n,1);cout<<b-e<<endl;}}
}int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;//cin>>t;while(t--){solve();    }return 0;
}

这个题就需要一点转化了。由于要求查询的是范围内放置的地雷种数,而线段树是不能直接用来维护这个信息的。所以可以考虑使用前缀和的思想,用线段树维护范围内每次放置地雷的开头个数和结尾个数,那么这个范围[l,r]内的地雷种数就是[1,r]上地雷的开头个数减去[1,l-1]上地雷的结尾个数。那么这两个信息汇总时就是和累加和一样处理即可,每次放地雷时就是分别去开头位置和结尾位置进行单点修改即可,所以put函数还要带着jobt参数表示这次修改的是开头还是结尾。同理,query函数也要带着jobt表示查询的类型。

三、无聊的数列

#include <bits/stdc++.h>
using namespace std;typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll>pll;const int MAXN=1e5+5;//对于在[l,r]上加等差数列
//差分数组中可以在[l]加首项,之后每个位置都加公差,最后[r+1]减末项//原数组
vector<int>a(MAXN);
//差分数组
vector<int>diff(MAXN);
//差分数组累加和
vector<ll>sum(MAXN<<2);
//懒信息
vector<ll>info(MAXN<<2);//懒更新
void lazy(int i,int v,int n)
{sum[i]+=v*n;info[i]+=v;
}//下发
void down(int i,int ln,int rn)
{if(info[i]!=0){lazy(i<<1,info[i],ln);lazy(i<<1|1,info[i],rn);info[i]=0;}
}//汇总
void up(int i)
{sum[i]=sum[i<<1]+sum[i<<1|1];
}void build(int l,int r,int i)
{if(l==r){sum[i]=diff[l];}else{int m=(l+r)>>1;build(l,m,i<<1);build(m+1,r,i<<1|1);up(i);}info[i]=0;
}//范围修改
void add(int jobl,int jobr,ll jobv,int l,int r,int i)
{if(jobl<=l&&r<=jobr){lazy(i,jobv,r-l+1);}else{int m=(l+r)>>1;down(i,m-l+1,r-m);if(jobl<=m){add(jobl,jobr,jobv,l,m,i<<1);}if(m+1<=jobr){add(jobl,jobr,jobv,m+1,r,i<<1|1);}up(i);}
}//范围查询
ll query(int jobl,int jobr,int l,int r,int i)
{if(jobl<=l&&r<=jobr){return sum[i];}int m=(l+r)>>1;down(i,m-l+1,r-m);ll ans=0;if(jobl<=m){ans+=query(jobl,jobr,l,m,i<<1);}if(m+1<=jobr){ans+=query(jobl,jobr,m+1,r,i<<1|1);}return ans;
}void solve()
{int n,m;cin>>n>>m;for(int i=1;i<=n;i++){cin>>a[i];}for(int i=1;i<=n;i++){diff[i]=a[i]-a[i-1];}build(1,n,1);int op;while(m--){cin>>op;if(op==1){ll l,r,k,d;cin>>l>>r>>k>>d;//开头加首项add(l,l,k,1,n,1);//中间加公差if(l+1<=r){add(l+1,r,d,1,n,1);   }//后一项减末项if(r+1<=n){add(r+1,r+1,-(k+d*(r-l)),1,n,1);}}else{int q;cin>>q;cout<<query(1,q,1,n,1)<<endl;}}
}int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;//cin>>t;while(t--){solve();    }return 0;
}

这个题因为只涉及单点查询,又因为每次范围增加是增加一个等差数列,所以可以考虑用线段树去维护差分数组的累加和,那么单点查询时只需要查[1,q]上的累加和即可。而对于在差分数组中增加等差数列的操作,通过观察等差数列的差分数组可以想到,方法就是在l位置加上首项,之后的每个位置都加公差,最后在r+1的位置减去末项即可。这里记得等差数列末项的公式是首项加项数减一乘公差即可。

四、方差

死去的高中数学还在追我()

#include <bits/stdc++.h>
using namespace std;typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll>pll;const int MAXN=1e5+5;//原数组
vector<double>a(MAXN);
//累加和
vector<double>sum(MAXN<<2);
//平方和
vector<double>square(MAXN<<2);
//懒信息
vector<double>info(MAXN<<2);//懒更新
void lazy(int i,double v,int n)
{square[i]+=n*v*v+2*v*sum[i];sum[i]+=v*n;info[i]+=v;
}//下发
void down(int i,int ln,int rn)
{if(info[i]!=0){lazy(i<<1,info[i],ln);lazy(i<<1|1,info[i],rn);info[i]=0;}
}//汇总
void up(int i)
{sum[i]=sum[i<<1]+sum[i<<1|1];square[i]=square[i<<1]+square[i<<1|1];
}void build(int l,int r,int i)
{if(l==r){sum[i]=a[l];square[i]=a[l]*a[l];}else{int m=(l+r)>>1;build(l,m,i<<1);build(m+1,r,i<<1|1);up(i);}info[i]=0;
}//范围增加
void add(int jobl,int jobr,double jobv,int l,int r,int i)
{if(jobl<=l&&r<=jobr){lazy(i,jobv,r-l+1);}else{int m=(l+r)>>1;down(i,m-l+1,r-m);if(jobl<=m){add(jobl,jobr,jobv,l,m,i<<1);}if(m+1<=jobr){add(jobl,jobr,jobv,m+1,r,i<<1|1);}up(i);}
}//范围查询
double query(int jobl,int jobr,int l,int r,int i,vector<double>&sum)
{if(jobl<=l&&r<=jobr){return sum[i];}int m=(l+r)>>1;down(i,m-l+1,r-m);double ans=0;if(jobl<=m){ans+=query(jobl,jobr,l,m,i<<1,sum);}if(m+1<=jobr){ans+=query(jobl,jobr,m+1,r,i<<1|1,sum);}return ans;
}void solve()
{int n,m;cin>>n>>m;for(int i=1;i<=n;i++){cin>>a[i];}build(1,n,1);int op;int x,y;double k;while(m--){cin>>op>>x>>y;;if(op==1){cin>>k;add(x,y,k,1,n,1);}else if(op==2){cout<<fixed<<setprecision(4)<<query(x,y,1,n,1,sum)/(y-x+1)<<endl;}else{double sq=query(x,y,1,n,1,square)/(y-x+1);double avg=query(x,y,1,n,1,sum)/(y-x+1);cout<<fixed<<setprecision(4)<<sq-avg*avg<<endl;}}
}int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;//cin>>t;while(t--){solve();    }return 0;
}

首先,平均数这个信息好办,就是用线段树维护累加和信息,每次查询范围累加和除以范围个数即可。但方差这个信息肯定是没办法直接用线段树维护的,那么就可以考虑对方差公式进行一下转化。具体的转化就是:

\frac{\sum (x-\bar{x})^{2}}{n}=\frac{\sum x^{2}-2\bar{x}\sum x+n\bar{x}}{n}=\frac{\sum x^{2}}{n}-2\bar{x}^{2}+\bar{x}^{2}=\frac{\sum x^{2}}{n}-\bar{x}^{2}

那么就可以考虑用线段树去维护平方和这个信息,然后再通过加工就能得到方差了。

又因为对于范围增加操作,范围上的平方和有:

\sum (x+v)^{2}=\sum (x^{2}+2xv+v^{2})=\sum x^{2}+2v\sum x+nv^{2}

所以在lazy函数里,范围平方和就是在原来的基础上加上两倍的v乘范围累加和,再加上范围个数乘以v的平方即可。

总结

线段树的题目还是要注意转化。

END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/94973.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/94973.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/94973.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode_27】移除元素

刷爆LeetCode系列LeetCode27题&#xff1a;github地址前言题目描述题目思路分析代码实现算法代码优化LeetCode27题&#xff1a; github地址 有梦想的电信狗 前言 本文用C实现LeetCode 第27题 题目描述 题目链接&#xff1a;https://leetcode.cn/problems/remove-element/ …

C++11语言(三)

一、引言上期我们介绍了C11的大部分特性。C11的初始化列表、auto关键字、右值引用、万能引用、STL容器的的emplace函数。要补充的是右值引用是不能取地址的&#xff0c;我们程序员一定要遵守相关的语法。操作是未定义的很危险。二、 仿函数和函数指针我们先从仿函数的形…

性能优化三剑客:`memo`, `useCallback`, `useMemo` 详解

性能优化三剑客&#xff1a;memo, useCallback, useMemo 详解 作者&#xff1a;码力无边各位React性能调优师&#xff0c;欢迎来到《React奇妙之旅》的第十二站&#xff01;我是你们的伙伴码力无边。在之前的旅程中&#xff0c;我们已经掌握了如何构建功能丰富的组件&#xff0…

好用的电脑软件、工具推荐和记录

固态硬盘读写测试 AS SSD Benchmark https://gitee.com/qlexcel/common-resource-backup/blob/master/AS%20SSD%20Benchmark.exe 可以测试SSD的持续读写、4K随机读写等性能。也可以测试HDD的性能。 操作非常简单&#xff0c;点击Start(开始)即可测试。 体积小&#xff0c;免安…

Spring Task快速上手

一. 介绍Spring Task 是Spring框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑&#xff0c;无需依赖额外组件&#xff08;如 Quartz&#xff09;&#xff0c;配置简单、使用便捷&#xff0c;适合处理周期性执行的任务&#xff08;如定时备份数据、定…

函数(2)

6.定义函数的终极绝杀思路&#xff1a;三个问题&#xff1a;1.我定义函数&#xff0c;是为了干什么事情 函数体、2.我干完这件事&#xff0c;需要什么才能完成 形参3.我干完了&#xff0c;调用处是否需要继续使用 返回值类型需要继续使用 必须写不需要返回 void小程序#include …

BGP路由协议(一):基本概念

###BGP概述 BGP的版本&#xff1a; BGP-1 RFC1105BGP-2 RFC1163BGP-3 RFC1267BGP-4 RFC1771 1994年BGP-4 RFC4271 2006年 AS Autonomous System 自治系统&#xff1a;由一个单一的机构或者组织所管理的一系列IP网络及其设备所构成的集合 根据工作范围的不同&#xff0c;动态路…

mit6.031 2023spring 软件构造 笔记 Testing

当你编码时&#xff0c;目标是使程序正常工作。 但作为测试设计者&#xff0c;你希望让它失败。 这是一个微妙但重要的区别。 为什么软件测试很难&#xff1f; 做不到十分详尽&#xff1a;测试一个 32 位浮点乘法运算 。有 2^64 个测试用例&#xff01;随机或统计测试效果差&am…

【Unity开发】Unity核心学习(三)

四、三维模型导入相关设置 1、Model模型页签&#xff08;1&#xff09;场景相关&#xff08;2&#xff09;网格相关&#xff08;3&#xff09;几何体相关2、Rig操纵&#xff08;骨骼&#xff09;页签 &#xff08;1&#xff09;面板基础信息&#xff08;i&#xff09;None&…

C#语言入门详解(17)字段、属性、索引器、常量

C#语言入门详解&#xff08;17&#xff09;字段、属性、索引器、常量前言一、字段 Field二、属性三、索引器四、常量内容来自刘铁猛C#语言入门详解课程。 参考文档&#xff1a;CSharp language specification 5.0 中文版 前言 类的成员是静态成员 (static member) 或者实例成…

Total PDF Converter多功能 PDF 批量转换工具,无水印 + 高效处理指南

在办公场景中&#xff0c;PDF 格式的 “不可编辑性” 常成为效率瓶颈 —— 从提取文字到格式转换&#xff0c;从批量处理到文档加密&#xff0c;往往需要多款工具协同。Total PDF Converter 破解专业版作为一站式 PDF 解决方案&#xff0c;不仅支持 11 种主流格式转换&#xff…

[Windows] WPS官宣 64位正式版(12.1.0.22525)全新发布!

[Windows] WPS官宣 64位正式版 链接&#xff1a;https://pan.xunlei.com/s/VOYepABmXVfXukzlPdp8SKruA1?pwdeqku# 自2024年5月&#xff0c;WPS 64位版本在WPS社区发布第一个内测体验安装包以来&#xff0c;在近一年多的时间里&#xff0c;经过超过3万名WPS体验者参与版本测试…

WinExec

函数原型&#xff1a; __drv_preferredFunction("CreateProcess","Deprecated. See MSDN for details") WINBASEAPI UINT WINAPI WinExec(__in LPCSTR lpCmdLine,__in UINT uCmdShow); preferred : 更好的 __drv_preferredFunction("CreateProcess…

基于GA遗传优化的双向LSTM融合多头注意力(BiLSTM-MATT)时间序列预测算法matlab仿真

目录 1.前言 2.算法运行效果图预览 3.算法运行软件版本 4.部分核心程序 5.算法仿真参数 6.算法理论概述 7.参考文献 8.算法完整程序工程 1.前言 时间序列预测是机器学习领域的重要任务&#xff0c;广泛应用于气象预报、金融走势分析、工业设备故障预警等场景。传统时间…

Multi-Head RAG: Solving Multi-Aspect Problems with LLMs

以下是对论文《Multi-Head RAG: Solving Multi-Aspect Problems with LLMs》的全面解析&#xff0c;从核心问题、方法创新到实验验证进行系统性阐述&#xff1a;​​一、问题背景&#xff1a;传统RAG的局限性​​传统检索增强生成&#xff08;RAG&#xff09;在处理​​多维度复…

Jenkins 全方位指南:安装、配置、部署与实战应用(含图解)

一、Jenkins 安装 1.1 系统要求 基础环境&#xff1a;Java 8 或 Java 11&#xff08;推荐&#xff09;、至少 2GB 内存、10GB 以上磁盘空间 支持系统&#xff1a;Windows、Linux&#xff08;Ubuntu/CentOS&#xff09;、macOS 网络端口&#xff1a;默认使用 8080 端口&…

以国产IoTDB为代表的主流时序数据库架构与性能深度选型评测

> &#x1f4a1; 原创经验总结&#xff0c;禁止AI洗稿&#xff01;转载需授权 > 声明&#xff1a;本文所有观点均基于多个领域的真实项目落地经验总结&#xff0c;数据说话&#xff0c;拒绝空谈&#xff01; 目录 引言&#xff1a;时序数据库选型的“下半场” 一、维…

7.2elementplus的表单布局与模式

基础表单<template><el-form ref"ruleFormRef" :model"form" :rules"rules" label-width"100px"><el-form-item label"用户名" prop"username"><el-input v-model"form.username"…

PyTorch实战(3)——PyTorch vs. TensorFlow详解

PyTorch实战&#xff08;3&#xff09;——PyTorch vs. TensorFlow详解0. 前言1. 张量2. PyTorch 模块2.1 torch.nn2.2 torch.optim2.3 torch.utils.data3. 使用 PyTorch 训练神经网络小结系列链接0. 前言 PyTorch 是一个基于 Torch 库的 Python 机器学习库&#xff0c;广泛用…

在win服务器部署vue+springboot + Maven前端后端流程详解,含ip端口讲解

代码打包与基本配置 首先配置一台win系统服务器&#xff0c;开放你前端和后端运行的端口&#xff0c;如80和8080 前端打包 前端使用vue3&#xff0c;在打包前修改项目配置文件&#xff0c;我使用的是vite所以是vite.config.js。 import { defineConfig } from vite import …