几次的省赛,成绩都不是很理想。不过这几次省赛的给我们留下了很多宝贵的经验: 首先发现的是线段树,每考必有: 今天我们学习的就是线段树: 线段树的功能是: 1、对一段数字进行累加。 2、对数字进行搜索。 3、将包含在区间int的元素x插入到树t中。 4、从线段树中删除元素x。 5、对线段树上的数据进行更新。 今天,我们要做的是poj3468: 题目大意:第一行输入n、m;第二行输入n个数据;接下来有m行分别输入字母与几个数据,如果的 字母是Q则输入l、r,表示查询下标为l~r的数据总和;字母为C则输入l,r,c,表示从下标为l到下标为r的数据加上c。 思路:线段树可以完成对数字的搜索,并且可以方便的数据进行更新,所以我们采用了线段树算法。 方法:
这道题,让我明白了一个问题,就是当你使用scanf()的时候,会比较省时间,而cin会比较不省时间。做了好久才正确理解了这题的意思,看来我应该多做点线段树的题目。嘿嘿~明天加油咯~
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
struct Point{
int l,r;
__int64 sum,p;//sum表示区间l到r的数据总和;p是区间l到r的增量
}T[400005];
__int64 map[400005];
void create(int u,int l,int r){
T[u].l = l;
T[u].r = r;
T[u].p = 0;//先赋值
if(l==r){//如果l==r说明递归到最后一个节点了
T[u].sum=map[l];
return;
}
int mid = (T[u].l+T[u].r)>>1;//右移相当于除以2,mid表示的就是区间之间的中点
create(u<<1,l,mid);
create(u<<1|1,mid+1,r);//u为下一个的节点。
T[u].sum = T[u<<1].sum+T[u<<1|1].sum;
}
void updata(int u,int l,int r,__int64 c){
if(T[u].l==l&&T[u].r==r){//说明到了那个区间了
T[u].p +=c;//给增量赋值,不加到sum上,减少时间
return;
}
T[u].sum = T[u].sum+(r-l+1)*c;
int mid = (T[u].l+T[u].r)>>1;
if(r<=mid)
updata(u<<1,l,r,c);
else if(l>mid)
updata(u<<1|1,l,r,c);
else
{
updata(u<<1,l,mid,c);
updata(u<<1|1,mid+1,r,c);
}
}
__int64 query(int u,int l,int r){
__int64 del = T[u].p;
if(T[u].l==l&&T[u].r==r)
return (T[u].sum + (r-l+1)*del);
else{
T[u<<1].p += T[u].p;
T[u<<1|1].p +=T[u].p;
T[u].sum += (T[u].r-T[u].l+1)*del;
T[u].p=0;
}
int mid = (T[u].l+T[u].r)>>1;
if(r<=mid)
return query(u<<1,l,r);
else if(l>mid)
return query(u<<1|1,l,r);
else
return query(u<<1,l,mid)+query(u<<1|1,mid+1,r);
}
int main(){
int n,m,i,j,k,l,r;
__int64 c;
char ch[7];
while(cin>>n>>m){
for(i=1;i<=n;i++)
scanf("%I64d",&map[i]);
create(1,1,n);
while(m--){
scanf("%s",ch);
if(ch[0]=='Q'){
scanf("%d%d",&l,&r);
printf("%I64d\n",query(1,l,r));
}
else{
scanf("%d%d%I64d",&l,&r,&c);
updata(1,l,r,c);
}
//getchar();
}
}
return 0;
}
这道题,让我明白了一个问题,就是当你使用scanf()的时候,会比较省时间,而cin会比较不省时间。做了好久才正确理解了这题的意思,看来我应该多做点线段树的题目。嘿嘿~明天加油咯~