做树状数组的题之前,需要做三道板子题:
板子题就不写题解了哈╮(╯▽╰)╭
#include
#include
#include
#include
#include
#include
#define int long long
using namespace std;
int n,q,a[1000005],c[1000005];
void update(int t,int v)
{
for (int x=t; x<=n; x+=x&-x) c[x]+=v;
}
int getsum(int t)
{
int ans=0;
for (int x=t; x; x-=x&-x) ans+=c[x];
return ans;
}
signed main()
{
scanf("%lld%lld",&n,&q);
for (int i=1; i<=n; i++) scanf("%lld",&a[i]),update(i,a[i]);
for (int i=1; i<=q; i++){
int x,l,r;
scanf("%lld%lld%lld",&x,&l,&r);
if (x==1) update(l,r);
if (x==2) printf("%lld\n",getsum(r)-getsum(l-1));
}
return 0;
}
#include
#include
#include
#include
#include
#include
#define int long long
using namespace std;
int n,q,a[1000005],c[1000005];
void update(int x,int v)
{
for (; x<=n; x+=x&-x) c[x]+=v;
}
int getsum(int x)
{
int sum=0;
for (; x>0; x-=x&-x) sum+=c[x];
return sum;
}
signed main()
{
scanf("%lld",&n);
scanf("%lld",&q);
int last=0;
for (int i=1; i<=n; i++) {scanf("%lld",&a[i]); update(i,a[i]-last); last=a[i];}
for (int i=1; i<=q; i++){
int f;
scanf("%lld",&f);
if (f==1) {
int x,y,v;
scanf("%lld%lld%lld",&x,&y,&v);
update(x,v); update(y+1,-v);
}
else{
long long ans; int x;
scanf("%lld",&x);
ans=getsum(x);
printf("%lld\n",ans);
}
}
}
#include
#include
#define ll long long
using namespace std;
int n,q;
ll a[1000005],c1[1000005],c2[1000005];
void update(int x,int v)
{
for (int X=x; X<=n;X+=X&-X) c1[X]+=v,c2[X]+=(ll)v*x;
}
ll getsum(int x)
{
ll sum=0;
for (int X=x; X>0; X-=X&-X) sum+=(ll)(x+1)*c1[X]-c2[X];
return sum;
}
int main()
{
scanf("%d%d",&n,&q);
for (int i=1; i<=n; i++) scanf("%lld",&a[i]),a[i]+=a[i-1];
while (q--){
char st[3];
scanf("%s",st);
if (st[0]=='2'){
int x,y;
scanf("%d%d",&x,&y);
printf("%lld\n",getsum(y)-getsum(x-1)+a[y]-a[x-1]);
}
else {
int x,y,v;
scanf("%d%d%d",&x,&y,&v);
update(x,v); update(y+1,-v);
}
}
return 0;
}
因为输入时题目已经帮我们排序排好了,而又经过一番推理得:若是排好的数据,则和y轴无关,当前星星的级数就是该星星前面所有x轴小于等于该星星的x轴大小的数量之和。接下来就可以愉快地码代码啦~~~
#include
#include
#include
#include
#include
#include
using namespace std;
int n,a[1000005],c[1000005],ans[1000005];
void update(int x,int v)
{
for (; x<=40000; x+=x&-x) c[x]+=v;
}
int getsum(int x)
{
int ans=0;
for (; x; x-=x&-x) ans+=c[x];
return ans;
}
int main()
{
scanf("%d",&n);
for (int i=1; i<=n; i++){
int x,y;
scanf("%d%d",&x,&y);
x++;
ans[getsum(x)]++;
update(x,1);
}
for (int i=1; i<=n; i++) printf("%d\n",ans[i-1]);
return 0;
}
将该题转化为括号序列,在一段区间种一种树相当于在 l l 的位置加入一个(,在 r r 的位置加入一个右括号。
维护两个树状数组,一个记录左括号,一个记录右括号,答案就呼之欲出了
#include
#include
#include
#include
#include
#include
using namespace std;
int n,m,c[1000005][2],a[1000005];
void update(int x,int y,int t)
{
for (; x<=n; x+=x&-x) c[x][t]+=y;
}
int getsum(int x,int t)
{
int ans=0;
for (; x; x-=x&-x) ans+=c[x][t];
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1; i<=m; i++){
int x,l,r;
scanf("%d%d%d",&x,&l,&r);
if (x==1) update(l,1,0),update(r,1,1);
if (x==2) printf("%d\n",getsum(r,0)-getsum(l-1,1));
}
return 0;
}
树状数组裸题啊~~,不写了
#include
#include
#include
#include
#include
#include
using namespace std;
int n,k,c[1000005];
char ch[1005];
void update(int x,int y)
{
for (; x<=n; x+=x&-x) c[x]+=y;
}
int getsum(int x)
{
int ans=0;
for (; x; x-=x&-x) ans+=c[x];
return ans;
}
int main()
{
scanf("%d%d",&n,&k);
for (int i=1; i<=k; i++){
scanf("%s",ch);
if (ch[0]=='A') {
int x;
scanf("%d",&x);
printf("%d\n",getsum(x));
}
if (ch[0]=='B'){
int x,y;
scanf("%d%d",&x,&y);
update(x,y);
}
if (ch[0]=='C'){
int x,y;
scanf("%d%d",&x,&y);
update(x,-y);
}
}
return 0;
}
高仿T2,不想多说╮(╯▽╰)╭
为什么越到后面越简单了呢╮(╯▽╰)╭
#include
#include
#include
#include
#include
#include
using namespace std;
int n,m,c[1000005][2];
void update(int x,int y,int t)
{
for (; x<=n; x+=x&-x) c[x][t]+=y;
}
int getsum(int x,int t)
{
int ans=0;
for (; x; x-=x&-x) ans+=c[x][t];
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1; i<=m; i++){
int x; scanf("%d",&x);
if (x==1) {
int l,r;
scanf("%d%d",&l,&r);
update(l,1,0); update(r,1,1);
}
if (x==2){
int t; scanf("%d",&t);
printf("%d\n",(getsum(t,0)-getsum(t-1,1))&1);
}
}
return 0;
}
好啦,就写这些辣,多写也没什么意思不是吗╮(╯▽╰)╭