hiho #1078 : 线段树的区间修改
题意:长度为n的序列上有两种操作
0 ql qr 输出区间[ql,qr]和
1 ql qr v 区间[ql,qr]赋值为v
线段树懒标基础题,我用分块写了一个,在本题数据竟然跑的飞快
#include<iostream> #include<cstdio> #include<cmath> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=1e5+5; typedef long long ll; int val[maxn],belong[maxn],l[maxn],r[maxn],inv[maxn]; ll ans[maxn]; int n,q,op,ql,qr,v,cnt,block; void update(int L,int R,int bt){ if(L==l[bt]&&R==r[bt]){ inv[bt]=v;ans[bt]=(ll)v*(R-L+1); return ; } if(inv[bt]){ rep(i,l[bt],L-1)val[i]=inv[bt]; rep(i,R+1,r[bt])val[i]=inv[bt]; rep(i,L,R)ans[bt]+=v-inv[bt],val[i]=v; inv[bt]=0; return ; } rep(i,L,R)ans[bt]+=v-val[i],val[i]=v; } void update(){ int b1=belong[ql],b2=belong[qr]; if(b1==b2)update(ql,qr,b1); else{ update(ql,r[b1],b1);b1++; while(b1<b2) update(l[b1],r[b1],b1),b1++; update(l[b2],qr,b2); } } ll query(int L,int R,int bt){ if(l[bt]==L&&r[bt]==R)return ans[bt]; if(inv[bt])return (ll)inv[bt]*(R-L+1); ll res=0; rep(i,L,R)res+=val[i]; return res; } ll query(){ ll res=0; int b1=belong[ql],b2=belong[qr]; if(b1==b2)return query(ql,qr,b1); res+=query(ql,r[b1],b1);b1++; while(b1<b2)res+=ans[b1++]; res+=query(l[b2],qr,b2); return res; } void init(){ block=sqrt(n);cnt=n/block; rep(i,0,n-1){ belong[i]=i/block; ans[belong[i]]+=val[i]; } rep(i,0,cnt-1)l[i]=i*block,r[i]=(i+1)*block-1; if(n%block){ l[cnt]=cnt*block,r[cnt]=n-1;cnt++; } } int main(){ scanf("%d",&n); rep(i,0,n-1)scanf("%d",val+i); init(); scanf("%d",&q); while(q--){ scanf("%d%d%d",&op,&ql,&qr); ql--;qr--; if(op){ scanf("%d",&v); update(); } else printf("%lld\n",query()); } return 0; }