1535:【例 1】数列操作
模板题
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=101000;
const int INF=0x3fffffff;
typedef long long LL;
#define lowbit(x) ((x)&(-x))
int tree[maxn];
int n,m;
void add(int x,int d){
while(x<=n){
tree[x]+=d;
x+=lowbit(x);
}
}
LL getsu(int x){
LL ans=0;
while(x>0){
ans+=tree[x];
x-=lowbit(x);
}
return ans;
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) {
int x;
scanf("%d",&x);
add(i,x);
}
int k,a,b;
while(m--){
scanf("%d %d %d",&k,&a,&b);
if(k==0) printf("%lld\n",getsu(b)-getsu(a-1));
else add(a,b);
}
return 0;
}
1536:【例 2】数星星 Stars
//二维的树状数组bushi
//认真读题呀!!!!!看给出数据的特征,是按照纵坐标从小到大排序的,纵坐标相同的是横坐标从小到大给出的
//也就是说,我们可以不管纵坐标,按照它给出的横坐标依次插入,并统计当前星星之前的横坐标小于它的星星个数。
观察输入数据的特点
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int n;
int c[100005];
int ans[100055];
int maxn=32001;
struct node{
int x,y;
}a[100005];
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int y)
{
while(x<=maxn)
{
c[x]+=y;
x+=lowbit(x);
}
}
int sum(int x)
{
int cnt=0;
while(x>0)
{
cnt+=c[x];
x-=lowbit(x);
}
return cnt;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
}
for(int i=1;i<=n;i++)
{
int wzx=a[i].x+1;
int jd=sum(wzx); //先计算个数,为什么不剪掉1,因为包括了正左、正下
update(wzx,1); //再进行更新
ans[jd]++;
}
for(int i=0;i<n;i++)
printf("%d\n",ans[i]);
return 0;
}
1537:【例 3】校门外的树

注意,这里不是点更新了,而是区间更新,区间查找,而对于区间更新:维护两个数组,一个负责开始,一个负责结尾
左右括号法。
对于每次操作[a,b],将位于a的左括号个数加一,位于b的右括号个数加一。
对于每次查询[a,b],定义X等于1到b的左括号个数,Y等于1到a−1的右括号个数,答案即为X−Y
https://blog.csdn.net/zhang14369/article/details/81071990
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
#define lowbit(x) ((x)&(-x))
using namespace std;
const int maxn=5e4+10;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
int n,m;
int k;
//其他的做法:
//https://www.cnblogs.com/ECJTUACM-873284962/p/7060158.html
//这道题需要维护两个 开两个数组来存一个是开始的点的数量,一个是结束的 ,然后随便搞一下,最后输出就可以了
int a[maxn],b[maxn];
int getsum(int l,int r){
int ans=0;
for(int i=r;i;i-=lowbit(i)) ans+=a[i];
for(int i=l-1;i;i-=lowbit(i)) ans-=b[i];
return ans;
}
int main(){
scanf("%d %d",&n,&m);
int l,r;
for(int i=0;i<m;i++){
scanf("%d %d %d",&k,&l,&r);
if(k==1) {
for(int i=l;i<=n+1;i+=lowbit(i)) a[i]++;
for(int i=r;i<=n+1;i+=lowbit(i)) b[i]++;
}
else {
printf("%d\n",getsum(l,r));
}
}
return 0;
}
另一道区间求和、区间查询:利用差分的思想
1548:【例 2】A Simple Problem with Integers

讲解:

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1e6+10;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
//这道题是模板题:区间求和、区间修改
//可以用线段树、也可以用树状数组
//感觉线段树简单一点,但是不好推
//用树状数组讲解:维护两个前缀和
//https://blog.csdn.net/gzcszzx/article/details/100539427
/*
维护两个前缀和,
S1[i]=d[i],S2[i]=d[i]*i
查询:位置Pos的前缀和就是(Pos+1)*S1中1到Pos的和 减去 S2中1到Pos的和,[L,R]=SS[R]-SS[L-1]
修改:[L,R]
S1:S1[L]+Tag,S1[R+1]-Tag
S2:S2[L]+Tag*L ,S2[R+1]-Tag*(R+1)
*/
LL n,m;
LL a[maxn],d[maxn]; //a[i]为原数组 d[i]为差分数组
LL c1[maxn],c2[maxn]; //两个前缀和
#define lowbit(x) ((x)&(-x))
void add(LL x,LL v){
LL p=x;
while(x<=n){
c1[x]+=v;
c2[x]+=p*v;
x+=lowbit(x);
}
}
LL getans(LL x){
LL ans=0,p=x;
while(x){
ans+=(p+1)*c1[x]-c2[x];
x-=lowbit(x);
}
return ans;
}
int main(){
scanf("%lld %lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
d[i]=a[i]-a[i-1];
add(i,d[i]);
}
while(m--){
int p;
scanf("%d",&p);
if(p==1){
LL l,r,c;
scanf("%lld %lld %lld",&l,&r,&c);
add(l,c);
add(r+1,-c);
}
if(p==2){
LL x,y;
scanf("%lld %lld",&x,&y);
printf("%lld\n",getans(y)-getans(x-1));
}
}
return 0;
}
1538:清点人数
模板题
数据时cin铁定超时,换用scanf问题就来了,用getchar()读回车不知为何会错,看到别人的博客,读字符是scanf(" %c",&op);这样的,前面多一个空格,也能解决换行符问题,记一下.
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
#define lowbit(x) ((x)&(-x))
using namespace std;
const int maxn=5e5+100;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
int n,k;
char a;
int op[maxn];
void add(int x,int k){
for(int i=x;i<=n;i+=lowbit(i)) op[i]+=k;
}
LL getans(int pos){
LL ans=0;
for(int i=pos;i;i-=lowbit(i)) ans+=op[i];
return ans;
}
int main(){
scanf("%d %d",&n,&k);
//getchar();
int m,p;
for(int i=0;i<k;i++){
scanf(" %c",&a);
//读数据时cin铁定超时,换用scanf问题就来了,用getchar()读回车不知为何会错,看到别人的博客,读字符是scanf(" %c",&op);这样的,前面多一个空格,也能解决换行符问题,记一下.
if(a=='A'){
scanf("%d",&m);
printf("%lld\n",getans(m));
}
else if(a=='B'){
scanf("%d %d",&m,&p);
add(m,p);
}
else if(a=='C'){
scanf("%d %d",&m,&p);
add(m,-p);
}
//getchar();
}
return 0;
}
1539:简单题

这题也是,区间更新,点查询-
表达的内容改变了:c[]记录的是这个位置的数改变了多少次,这道题也可以用线段树做
但是如果两种操作不反转的话:差分的思路??
树状数组维护差分数组
差分数组修改区间
只需要在区间左端点加上修改的值 add(l,1);
在右端点之后减去修改的值就好了 add(r+1,-1);
求某个位置上的值
就是这个位置之前(包括这个位置)的和 getans(l)%2
也符合树状数组里面的sum
就不需要做差了
最后按照%2来输出就好了
因为翻转两次之后会回到原来的情况
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
#define lowbit(x) ((x)&(-x))
using namespace std;
const int maxn=1e5+10;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
//需要让数组01反转
//而且反转的是区间,
int c[maxn];
//用C[i]表示对其区间表示范围内的元素修改了几次 !!!不要忘了这种啊
//故可以用类似于树状数组中点修改的操作
int n,m;
//呜呜呜呜我错了,这是区间修改和点查询,两种的操作要反过来
void add(int x,int k){
while(x<=n){
c[x]+=k;
x+=lowbit(x);
}
}
int getans(int x){
int ans=0;
while(x){
ans+=c[x];
x-=lowbit(x);
}
return ans;
}
int main(){
scanf("%d %d",&n,&m);
int t,l,r;
while(m--){
scanf("%d",&t);
if(t==1){
scanf("%d %d",&l,&r);
add(l,1);
add(r+1,-1); //如果不反过来的话为甚恶魔是这样呢 ,减少一次更新的情况
}
else if(t==2){
scanf("%d",&l);
printf("%d\n",getans(l)%2);
}
}
return 0;
}
1540:打鼹鼠_二维树状数组

二维树状数组,最后一个点过不了
有两个注意的细节:
1)再add的时候,数据范围是x<=maxn,tempy<=maxn
2)在计算结果的时候,是需要这样减去的ask(c,d)-ask(a-1,d)-ask(c,b-1)+ask(a-1,b-1)
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
#define lowbit(x) ((x)&(-x))
using namespace std;
const int maxn=5004;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
int mp[maxn][maxn];
int n,m;
//!!!!为什么最后一个点过不了!!!!
void add(int x,int y,int xx){
int y1;
while(x<=maxn){
y1=y;
while(y1<=maxn){
mp[x][y1]+=xx;
y1+=lowbit(y1);
}
x+=lowbit(x);
}
}
LL ask(int x,int y){
LL ans=0;
while(x){
int temp=y;
while(temp){
ans+=mp[x][temp];
temp-=lowbit(temp);
}
x-=lowbit(x);
}
return ans;
}
int main(){
scanf("%d %d",&n,&m);
int op,xx,c,d,a,b;
while(scanf("%d",&op)!=EOF){
if(op==1){
scanf("%d %d %d",&a,&b,&xx);
add(a,b,xx);
}
else if(op==2){
scanf("%d %d %d %d",&a,&b,&c,&d);
printf("%lld\n",ask(c,d)-ask(a-1,d)-ask(c,b-1)+ask(a-1,b-1));
//这样减的!!!!!
}
}
return 0;
}
posted on
浙公网安备 33010602011771号