树状数组的一个例题:一组数据的单点修改区间查询操作。
这里是看到了__stdcall的这篇博客才明白。(只是了解了目前的这种解法还不敢说完全明白蒟蒻瑟瑟发抖)。
首先第一步便是把所有的操作都给他变成查询或者修改操作,然后查询操作因为是区间查询就给他改成两个查询然后进行标记来把这个操作从区间和变成前缀和相差。
- 合并问题的时候统计“加上的值的前缀和”,只能统计左边区间内的修改操作,改动查询结果的时候,只能修改右边区间内的查询结果。因为只有左边区间内的修改值对右边区间内的查询结果的影响还没有统计。(一开始就这里不太明白,看到这句话之后就了解了)
这个查询和修改的时间顺序已经是排好的就是按照输入顺序, 而且在归并的时候不管是重的或者当前区间没有统计到的都会被计算到这个区间里面去(学的还是太肤浅了呀)。
#include <bits/stdc++.h>
using namespace std;
struct Node
{
long long val;
int id,typ;
bool operator<(const Node &x)const{
return id!=x.id?id<x.id:typ<x.typ;
}
};
Node a[2000000],b[2000000];
long long int tot,totx,ans[2000000];
void CDQ(int l,int r)
{
if(l==r)
return ;
int M=(l+r)>>1;
CDQ(l,M),CDQ(M+1,r);
int k1=l,k2=M+1;
long long int sum=0;
for(int i=l;i<=r;i++)
{
if(k1<=M&&a[k1]<a[k2]||k2>r)
{
if(a[k1].typ==1)
sum+=a[k1].val;
b[i]=a[k1++];
}
else
{
if(a[k2].typ==2)ans[a[k2].val]-=sum;
else if(a[k2].typ==3)ans[a[k2].val]+=sum;
b[i]=a[k2++];
}
//cout<<sum<<endl;
}
/*for(int i=l;i<=r;i++)
{
// a[i]=b[i];
cout<<a[i].id<<' '<<a[i].val<<' '<<a[i].typ<<' '<<'|'<<' ';
}
cout<<endl;*/
for(int i=l;i<=r;i++)
{
a[i]=b[i];
//cout<<a[i].id<<' '<<a[i].val<<' '<<a[i].typ<<' '<<'|'<<' ';
}
//cout<<endl;
}
int main()
{
tot=0,totx=0;
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
tot++;
a[tot].id=i,a[tot].typ=1;
scanf("%d",&a[tot].val);
}
for(int i=1;i<=m;i++)
{
tot++;
int t;
scanf("%d",&t);
a[tot].typ=t;
if(t==1)
{
scanf("%d%lld",&a[tot].id,&a[tot].val);
}
else
{
totx++;
int l,r;
scanf("%d%d",&l,&r);
a[tot].id=l-1,a[tot].val=totx;
tot++;
a[tot].typ=3,a[tot].id=r,a[tot].val=totx;
}
}
/*for(int i=1;i<=tot;i++)
{
cout<<a[i].id<<' '<<a[i].val<<' '<<a[i].typ<<' '<<'|'<<' ';
}
cout<<endl;*/
CDQ(1,tot);
for(int i=1;i<=totx;i++)
cout<<ans[i]<<endl;
return 0;
}