什么题可以使用线段树呢?
线段树要满足一下几个性质:
1.操作可合并
2.查询可合并
3.可以在很短的时间合并操作
线段树没啥可说的,就直接贴份代码算了(区间修改,区间查询)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
struct lxy{
long long num,tag;
int lson,rson;
int l,r;
}b[400005];
int ini[100005];
int n,m,cnt=0;
int readit()
{
char a;
int x=1,num=0;
a=getchar();
while((a<'0'||a>'9')&&a!='-')a=getchar();
if(a=='-')x=-1,a=getchar();
while(a<='9'&&a>='0')
{
num=num*10+a-'0';
a=getchar();
}
return num*x;
}
void update(int u)
{
b[u].num=b[b[u].rson].num+b[b[u].lson].num;
}
void pushdown(int u)
{
if(b[u].tag==0)return;
int y=b[u].tag;
b[b[u].lson].num+=y*(b[b[u].lson].r-b[b[u].lson].l+1);
b[b[u].rson].num+=y*(b[b[u].rson].r-b[b[u].rson].l+1);
b[b[u].lson].tag+=y;
b[b[u].rson].tag+=y;
b[u].tag=0;
}
void build(int &k,int l,int r)
{
k=++cnt;
b[k].l=l;b[k].r=r;
if(l==r)
{
b[k].num=ini[l];
return;
}
int mid=(l+r)/2;
build(b[k].lson,l,mid);
build(b[k].rson,mid+1,r);
update(k);
}
void modify(int u,int ql,int qr,int x)
{
pushdown(u);
if(ql==b[u].l&&qr==b[u].r)
{
b[u].num+=x*(b[u].r-b[u].l+1);
b[u].tag+=x;
return;
}
int mid=(b[u].l+b[u].r)/2;
if(ql>mid) modify(b[u].rson,ql,qr,x);
else if(qr<=mid) modify(b[u].lson,ql,qr,x);
else {modify(b[u].rson,mid+1,qr,x);modify(b[u].lson,ql,mid,x);}
update(u);
}
long long ques(int u,int ql,int qr)
{
pushdown(u);
if(b[u].l==ql&&b[u].r==qr)
return b[u].num;
int mid=(b[u].l+b[u].r)/2;
long long ret=0;
if(ql>mid) ret+=ques(b[u].rson,ql,qr);
else if(qr<=mid) ret+=ques(b[u].lson,ql,qr);
else ret+=ques(b[u].rson,mid+1,qr)+ques(b[u].lson,ql,mid);
update(u);
return ret;
}
int main()
{
int root=1;
n=readit();m=readit();
for(int i=1;i<=n;i++)
ini[i]=readit();
build(root,1,n);
for(int i=1;i<=m;i++)
{
int x;
x=readit();
if(x==1)
{
int a1,a2,a3;
a1=readit();a2=readit();a3=readit();
modify(root,a1,a2,a3);
}
else
{
int a1,a2;
a1=readit();a2=readit();
printf("%lld\n",ques(root,a1,a2));
}
}
}