POJ - 3468 A Simple Problem with Integers
刚开始学习线段树,再次以本题为例,做点笔记
题意:题目有两种操作,一种是询问[l,r]区间的和,另一种是[l,r]区间上的每一位数都加上C
分析:显然,直接将数字C加到区间上的每一位数上比较耗时,效率也比较低,所以我们要另辟蹊径,那就是lazy操作。
lazy操作的意思就是先不将[l,r]区间的数上都加上C,也就是不直接将树的根的每一数+C,而是将+C这个标记推到他的两个子节点上,并将子节点更新sum[rt<<1]+=(tree[rt<<1].r-tree[rt<<1].l+1)*C(右节点同理),add[rt<<1]+=add[rt],add[rt]=0;这样做的话,只有这个区间被用到的时候,才会去用这个区间的子区间来更新他自己的区间和,大大的提高了效率
//pushdown void pushdown(int rt){ if(add[rt]){ add[rt<<1]+=add[rt]; add[rt<<1|1]+=add[rt]; sum[rt<<1]+=1LL*(tree[rt<<1].r-tree[rt<<1].l+1)*add[rt]; sum[rt<<1|1]+=1LL*(tree[rt<<1|1].r-tree[rt<<1|1].l+1)*add[rt]; add[rt]=0; } }
因为做了lazy操作,所以本个节点被使用时,才会被更新节点信息,所以在进行query时,必须使用pushdown函数,来下推标记
下面是个人代码
#define debug #include<stdio.h> #include<math.h> #include<cmath> #include<queue> #include<stack> #include<string> #include<cstring> #include<string.h> #include<algorithm> #include<iostream> #include<vector> #include<functional> #include<iomanip> #include<map> #include<set> #define pb push_back #define dbg(x) cout<<#x<<" = "<<(x)<<endl; using namespace std; typedef long long ll; typedef pair<int,int> pii; typedef pair<ll,ll>PLL; typedef pair<int,ll>Pil; const ll INF = 0x3f3f3f3f; const double inf=1e8+100; const double eps=1e-8; const int maxn =1e6; const int N = 510; const ll mod=1e9+7; //------ //define struct node{ int l,r; }tree[maxn<<2]; ll sum[maxn<<2],add[maxn<<2]; //pushup void pushup(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } //pushdown void pushdown(int rt){ if(add[rt]){ add[rt<<1]+=add[rt]; add[rt<<1|1]+=add[rt]; sum[rt<<1]+=1LL*(tree[rt<<1].r-tree[rt<<1].l+1)*add[rt]; sum[rt<<1|1]+=1LL*(tree[rt<<1|1].r-tree[rt<<1|1].l+1)*add[rt]; add[rt]=0; } } //buildtree void build(int l,int r,int rt) { tree[rt].l=l; tree[rt].r=r; add[rt]=0; if(l==r) { //gra[rt]=a[l]; scanf("%lld",&sum[rt]); return; } int m=l+r>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); pushup(rt); } //update void update(int L,int R,int C,int rt){ if(tree[rt].l==L&&tree[rt].r==R){ add[rt]+=C; sum[rt]+=1ll*C*(R-L+1); return; } if(tree[rt].l==tree[rt].r)return; pushdown(rt); int m=tree[rt].l+tree[rt].r>>1; if(R<=m){ update(L,R,C,rt<<1); }else if(L>m){ update(L,R,C,rt<<1|1); }else{ update(L,m,C,rt<<1); update(m+1,R,C,rt<<1|1); } pushup(rt); } //query ll query(int L,int R,int rt) { if(L==tree[rt].l&&R==tree[rt].r){ return sum[rt]; } pushdown(rt); ll ans=0; int m=tree[rt].l+tree[rt].r>>1; if(R<=m){ ans+=query(L,R,rt<<1); }else if(L>m){ ans+=query(L,R,rt<<1|1); }else{ ans+=query(L,m,rt<<1); ans+=query(m+1,R,rt<<1|1); } return ans; } //solve void solve() { int n,t; while(~scanf("%d%d",&n,&t)){ build(1,n,1); while(t--){ char mark[2]; int A,B,C; scanf("%s",&mark); if(mark[0]=='Q'){ scanf("%d%d",&A,&B); printf("%lld\n",query(A,B,1)); }else{ scanf("%d%d%d",&A,&B,&C); update(A,B,C,1); } } } } //main int main() { // ios_base::sync_with_stdio(false); #ifdef debug freopen("in.txt", "r", stdin); // freopen("out.txt","w",stdout); #endif // cin.tie(0); // cout.tie(0); solve(); /* #ifdef debug fclose(stdin); fclose(stdout); system("out.txt"); #endif */ return 0; }