算法--线段树

几次的省赛,成绩都不是很理想。不过这几次省赛的给我们留下了很多宝贵的经验: 首先发现的是线段树,每考必有: 今天我们学习的就是线段树: 线段树的功能是: 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。 思路:线段树可以完成对数字的搜索,并且可以方便的数据进行更新,所以我们采用了线段树算法。 方法:
#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会比较不省时间。做了好久才正确理解了这题的意思,看来我应该多做点线段树的题目。嘿嘿~明天加油咯~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值