【树状数组区间加+区间查询模板】洛谷P3372

虽然说这道题线段树很好做,但毕竟树状数组常数小又好写,所以还是写个模板吧。

区间加转为前缀加

区间和转为前缀和

我们讨论一个1~k的区间加x对于一个前缀和val【i】的影响

对于所有k<i的更新,对val[i]的贡献为val[i]+=k*x

对于所有k>=i的更新,对val[i]的贡献为val[i]+=i*x

所以我们维护记录两个数组,对于每次更新

a[k]+=x;b[k]+=k*x;

所以对于一个值的前缀和val[i]=b[1~i]+(a[i+1]~a[now])*i;

然后询问的时候前缀减一减就行了

程序:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
int n,m;
ll val,f[200000],g[200000],s[200000];
int lowbit(int x){return (x&-x);}
void update1(int x,int v)
{
  while (x<=n)
  {
  	f[x]+=v;
  	x+=lowbit(x);
  }
  return;
}
void update2(int x,int v)
{
  while (x<=n)
  {
  	g[x]+=v;
  	x+=lowbit(x);
  }
  return;
}
ll query(int x)
{
  ll sum=0;
  while (x>0)
  {
  	sum+=f[x];
  	x-=lowbit(x);
  }
  return sum;
}
ll query2(int x)
{
  ll sum=0;
  while (x>0)
  {
  	sum+=g[x];
  	x-=lowbit(x);
  }
  return sum;
}
int main()
{
  scanf("%d%d",&n,&m);
  int x;
  for (int i=1;i<=n;i++) scanf("%d",&s[i]),s[i]+=s[i-1];
  for (int i=1;i<=m;i++)
   {
  	int ch,x,y;
    scanf("%d%d%d",&ch,&x,&y);
    if (ch==1)
	{scanf("%lld",&val);update1(x,val); update1(y+1,-val);
	update2(x,x*val);update2(y+1,-(y+1)*val);}
    else
	{
	  ll ans1=s[y]+query(y)*(y+1)-query2(y);
	  ll ans2=s[x-1]+query(x-1)*x-query2(x-1);
	  printf("%lld\n",ans1-ans2);
	}
  }
  return 0;
}
时间: 2024-10-14 00:57:49

【树状数组区间加+区间查询模板】洛谷P3372的相关文章

【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询

题目描述 给出一棵n个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1. 定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目. 现有m次操作,每次为一下三种之一: RELEASE x:对x执行一次感染: RECENTER x:把根节点改为x,并对原来的根节点执行一次感染: REQUEST x:询问x子树中所有节点感染代价的平均值. 输入 输入的第一行包含两个整数n和m,分别代表局域网中计算机的数量,以及操作和询问的总数.接下来n-1行,

【bzoj5173】[Jsoi2014]矩形并 扫描线+二维树状数组区间修改区间查询

题目描述 JYY有N个平面坐标系中的矩形.每一个矩形的底边都平行于X轴,侧边平行于Y轴.第i个矩形的左下角坐标为(Xi,Yi),底边长为Ai,侧边长为Bi.现在JYY打算从这N个矩形中,随机选出两个不同的矩形,并计算它们的并的大小.JYY想知道,交的大小的期望是多少.换句话说即求在所有可能的选择中,两个矩形交的面积的平均大小是多大. 输入 输入一行包含一个正整数N. 接下来N行,每行4个整数,分别为Xi,Yi,Ai,Bi 2 < =  N < =  2*10^5, 0 < =  Xi,

树状数组 区间修改+区间查询

其实直到不久前都几乎不会用树状数组,请教了PPZ大佬之后终于懂了一点点. 然后小蒟蒻现在才知道了树状数组区间修改+区间查询的方法QAQ 传送门 Codevs 线段树练习3 //Twenty #include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<queu

POJ 1195-Mobile phones(二维树状数组-区间更新区间查询)

Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 17661   Accepted: 8173 Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided into squares. The

树状数组区间更新区间查询以及gcd的logn性质

题目描述 给你一个长为n的序列a m次查询 每次查询一个区间的所有子区间的gcd的和mod1e9+7的结果 输入描述: 第一行两个数n,m之后一行n个数表示a之后m行每行两个数l,r表示查询的区间 输出描述: 对于每个询问,输出一行一个数表示答案 示例1 输入 5 7 30 60 20 20 20 1 1 1 5 2 4 3 4 3 5 2 5 2 3 输出 30 330 160 60 120 240 100 说明 [1,1]的子区间只有[1,1],其gcd为30[1,5]的子区间有:[1,1]

bzoj 3779 重组病毒 —— LCT+树状数组(区间修改+区间查询)

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779 RELEASE操作可以对应LCT的 access,RECENTER则是 makeroot: 考虑颜色数,把一条实边变成虚边,子树+1,虚变实子树-1: 但有换根操作,怎么维护子树? 也可以用 dfs 序线段树维护,其实换 rt 只是 splay 的根方向改变,对应的子树还是可以找到的: 注意虚边变实或实边变虚时要找子树,不是直接找那个儿子,而是找那个儿子所在 splay 的根: 然后

树状数组区间更新区间查询

1 void ins(int k,int x,int t){ 2 for (; x<=tot; x+=x&-x) c[k][x]+=t; 3 } 4 ll getsum(int k,int x){ 5 ll t=0; for (; x; x-=x&-x) t+=c[k][x]; return t; 6 } 7 void mdy(int x,int y,int z){ 8 ins(0,x,z); ins(1,x,z*(x-1)); ins(0,y+1,-z); ins(1,y+1,-z

树状数组区间更新

在今天的文章开始之前,给大家提一个建议,由于线段树和树状数组这两个结构的分析有很多联系,因此,建议没有看前几篇文章的朋友一定需要了解一下前面的内容.链接如下: 线段树+RMQ问题第二弹 线段树第二弹(区间更新) 树状数组(Binary Indexed Tree,BIT) 上篇文章我们讨论了树状数组的基本结构以及它最擅长的两个功能:单点更新和区间求和,今天,我们来接着上一篇文章的内容继续深入研究.上篇文章我们是将树状数组和线段树进行对比讲解的,既然线段树的章节我们介绍了区间求和.区间最值.单点更新

hdu 1116 敌兵布阵(树状数组区间求最值)

题意: 给出一行数字,然后可以修改其中第i个数字,并且可以询问第i至第j个数字的和(i <= j). 输入: 首行输入一个t,表示共有t组数据. 接下来每行首行输入一个整数n,表示共有n个数字. 接下来每行首先输入一个字符串,如果是”Add”,接下来是两个整数a,b,表示给第i个数增加b.如果是”Query”,接下来是两个整数a,b,表示查询从第i个数到第j个数之间的和.如果是”End”,表示这组数据结束. 输出: 每组数据首先输出”Case X: ”,其中X表示第x组数. 每次查询,输出计算结