东北四省赛2019 H

编程入门 行业动态 更新时间:2024-10-16 18:29:15

东北<a href=https://www.elefans.com/category/jswz/34/900316.html style=四省赛2019 H"/>

东北四省赛2019 H

看了下题解思路才做出来的,一开始根本没有思路,还以为是线段树维护。
要掌握分析题目的方法:先在样例上尝试,各种方法,并且结合题目,看上去不是线段树就是树状数组,并且也不是简单的维护前缀和,并且有区间修改的操作,想到维护差分数组的树状数组。
最后要思路清晰得得出结论,便可找到合适的算法或数据结构解决,此题结论便是:构造差分数组,维护两个树状数组,一个是普通差分数组,另外一个是只维护大于0值的差分数组。

在这里总结一下个人对树状数组与线段树区别的理解:

树状数组(1)复杂度稳定O(logn),常数小,比线段树快,(2)且不用开四倍空间,(3)而且个人感觉树状数组好写(线段树懒标记难写,wtcl)。
而线段树的优点便是能够进行很多神奇操作,比树状数组的用途广。

总结下树状数组的两种基本用法:

1.直接维护数组,可进行的操作有区间查询单点修改。并且线段树的查询区间是前缀和。
2.维护差分数组。由于差分数组的特点,对原数组的区间修改,在差分数组中只需要修改两个点即 左端点和右端点的右一位。所以相当于能对原数组进行区间修改 和单点(原数组)查询(就是差分数组前缀和)了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lowbit(x) ((x)&(-x))
const int N = 1e5+10;
ll tree[N],a[N],n,m,b[N],tree2[N];
void update(int x,int k)
{while(x<=n){tree[x]+=k;x+=lowbit(x);}
}
void update2(int x,int k)
{while(x<=n){tree2[x]+=k;x+=lowbit(x);}
}
ll query(int x)
{ll sum=0;while(x){sum+=tree[x];x-=lowbit(x);}return sum;
}
ll query2(int x)
{ll sum=0;while(x){sum+=tree2[x];x-=lowbit(x);}return sum;
}
int main()
{int t;cin>>t;while(t--){memset(tree,0,sizeof(tree));memset(tree2,0,sizeof(tree2));scanf("%lld %lld",&n,&m);for(int i=1;i<=n;i++){scanf("%lld",&a[i]);b[i]=a[i]-a[i-1];if(b[i]>0)update(i,b[i]);update2(i,b[i]);}while(m--){int flag,l,r,k;scanf("%d",&flag);if(flag==1){scanf("%d %d %d",&l,&r,&k);update2(l,k);update2(r+1,-k);b[l]+=k;if(b[l]>=k){update(l,k);}else if(b[l]>0){update(l,b[l]);}if(b[r+1]>=k){update(r+1,-k);}else if(b[r+1]>0){update(r+1,-b[r+1]);}b[r+1]-=k;}else{scanf("%d %d",&l,&r);printf("%lld\n",query2(l)+query(r)-query(l));}}}return 0;
}

更多推荐

东北四省赛2019 H

本文发布于:2024-02-11 14:58:19,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1681578.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:四省

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!