线段树的模板题,先给一列数,然后给一些操作,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;
}