线段树的模板题,先给一列数,然后给一些操作,Q操作查询[l,r]区间和,C操作把区间[l,r]全部加上C。最近在学伸展树,就重新把这题做了一下。用伸展树的话,以区间中间点为下表,区间和为键值建树,左孩子记左区间,右孩子记右区间。同时为了处理方便,引入编号为0和n+1的节点。每次操作时,把节点l-1伸展到根,把r+1伸展到根节点的右孩子,这样要处理的区间就被包含在根节点和他右孩子之间了,Q操作就直接查询个和,C操作就上标记,恶心一点的就是旋转中标记的下传,不过这个仔细想想也好理解。
上面是伸展树写的下面是原来用线段树写的,不得不说这题还是线段树写比较合适..代码短跑得还快...而且写伸展树的时候用C++交莫名其妙的WA&TLE了一下午,换G++竟然擦边过了,好不科学-
下面上代码,先是伸展树的
#include <iostream> #include <cstdio> #include <cstring> typedef long long ll; using namespace std; const int maxn=100000+6; int pre[maxn],ch[maxn][2]; ll key[maxn]; int add[maxn]; int size[maxn]; ll val[maxn]; int a[maxn]; int root; int n,m; int l,r; void pushup(int r) { key[r]=key[ch[r][0]]+key[ch[r][1]]+(ll)val[r]+(ll)add[r]; size[r]=size[ch[r][0]]+size[ch[r][1]]+1; } void pushdown(int r) { int v; if (add[r]) { val[r]+=add[r]; if (ch[r][0]!=-1) { v=ch[r][0]; add[v]+=add[r]; key[v]+=((ll)add[r]*(ll)size[v]); } if (ch[r][1]!=-1) { v=ch[r][1]; add[v]+=add[r]; key[v]+=((ll)add[r]*(ll)size[v]); } add[r]=0; pushup(r); } } void build(int l,int r,int id) { if (id==-1) root=(l+r)>>1; if (l==r) { key[l]=(ll)a[l]; size[l]=1; pre[l]=id; ch[l][0]=ch[l][1]=-1; } else { int m=(l+r)>>1; pre[m]=id; if (m>l)ch[m][0]=(l+m-1)>>1,build(l,m-1,m); else ch[m][0]=-1; if (m<r)ch[m][1]=(m+1+r)>>1,build(m+1,r,m); else ch[m][1]=-1; pushup(m); } } void rotate(int x,int kind) { int y=pre[x]; pushdown(y); pushdown(x); ch[y][!kind]=ch[x][kind]; pre[ch[x][kind]]=y; if (pre[y]!=-1) { ch[pre[y]][ch[pre[y]][1]==y]=x; } pre[x]=pre[y]; ch[x][kind]=y; pre[y]=x; pushup(y); pushup(x); } void splay(int r,int tgt) { while(pre[r]!=tgt) { if(pre[pre[r]]==tgt) { rotate(r,ch[pre[r]][0]==r); } else { int y=pre[r]; int kind=ch[pre[y]][0]==y; if (ch[y][kind]==r) { rotate(r,!kind); rotate(r,kind); } else { rotate(y,kind); rotate(r,kind); } } } if (tgt==root) pushup(root); if (tgt==-1) root=r; } ll query(int r) { pushdown(r); return key[r]; } int main() { // freopen("in.txt","r",stdin); while(scanf("%d%d",&n,&m)!=EOF) { memset(add,0,sizeof add); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); val[i]=a[i]; } root=-1; build(0,n+1,root); // print(root); // cout<<endl; int num; char type[10]; for (int i=1;i<=m;i++) { scanf("%s%d%d",type,&l,&r); splay(l-1,-1); splay(r+1,root); if (type[0]=='C') { scanf("%d",&num); add[ch[ch[root][1]][0]]+=num; key[ch[ch[root][1]][0]]+=((ll)size[ch[ch[root][1]][0]]*(ll)num); } else { printf("%lld\n",query(ch[ch[root][1]][0])); } } } return 0; }
include <iostream> #include <algorithm> #include <cstdio> #include <memory.h> #include <cmath> #include <string> using namespace std; #define lson id<<1,l,m #define rson id<<1|1,m+1,r #define ll long long const int maxn=100000+10; ll sum[maxn<<2]; ll a[maxn]; int add[maxn<<2]; int n,m; void pushup(int id) { sum[id]=sum[id<<1]+sum[id<<1|1]; } void pushdown(int id,int m) { if (add[id]) { //add[id<<1]=add[id<<1|1]=add[id]; add[id<<1]+=add[id]; add[id<<1|1]+=add[id]; sum[id<<1]=sum[id<<1]+(ll)add[id]*(m-(m>>1)); sum[id<<1|1]=sum[id<<1|1]+(ll)add[id]*(m>>1); add[id]=0; } } void build(int id,int l,int r) { add[id]=0; if (l==r) { scanf("%lld",&sum[id]); return; } int m=(l+r)>>1; build(lson); build(rson); pushup(id); } void updata(int L,int R,int c,int id,int l,int r) { if (L<=l && r<=R) { add[id]+=c; sum[id]+=((ll)c*(r-l+1)); return ; } pushdown(id,r-l+1); int m=(l+r)>>1; if (L<=m) updata(L,R,c,lson); if (R>m) updata(L,R,c,rson); pushup(id); } ll query(int L,int R,int id,int l,int r) { if (L<=l && r<=R) { return sum[id]; } pushdown(id,r-l+1); ll ret=0; int m=(l+r)>>1; if (L<=m) ret+=query(L,R,lson); if (R>m) ret+=query(L,R,rson); return ret; } int main() { //freopen("a.in","r",stdin); while (~scanf("%d%d",&n,&m)) { build(1,1,n); char op[4]; int a,b,c; for (int i=1; i<=m; i++) { scanf("%s",op); if (op[0]=='Q') { scanf("%d%d",&a,&b); printf("%lld\n",query(a,b,1,1,n)); } else { scanf("%d%d%d",&a,&b,&c); updata(a,b,c,1,1,n); } } } return 0; }