线段树单点更新+区间更新+离散化

线段树单点更新

http://poj.org/problem?id=3264

题意:

给定Q(1 ≤ Q≤ 200,000)个数A1,A2… AQ,,多次求任一区间Ai–Aj中最大数和最小数的差。

#include<stdio.h>
#include<algorithm>
#define MAX 200009
#define INF 0xffffff0
using namespace std;
int num[MAX],minV,maxV;
struct Node{
	int minV;
	int maxV;
	int L;
	int R;
	int mid(){
		return (L+R)/2;
	}
}tree[MAX*4];
void build(int root, int s,int e){
	tree[root].L=s;
	tree[root].R=e;
	tree[root].minV=INF;
	tree[root].maxV=-INF;
	if(tree[root].L!=tree[root].R){
		build(root*2,s,tree[root].mid());
		build(root*2+1,tree[root].mid()+1,e);
	}
}
void insert(int root, int pos, int val){
	if(tree[root].L==tree[root].R){
		tree[root].minV=tree[root].maxV=val;
		return;
	}
	tree[root].minV=min(tree[root].minV,val);
	tree[root].maxV=max(tree[root].maxV,val);
	if(pos<=tree[root].mid()){
		insert(root*2, pos, val);
	}else{
		insert(root*2+1,pos,val);
	}
}
void query(int root, int s, int e){
	if(tree[root].minV>=minV&&tree[root].maxV<=maxV){
		return;
	}
	if(tree[root].L==s&&tree[root].R==e){
		minV=min(tree[root].minV,minV);
		maxV=max(tree[root].maxV,maxV);
		return ;
	}
	if(e<=tree[root].mid()){
		query(root*2,s,e);
	}else if(s>tree[root].mid()){
		query(root*2+1,s,e);
	}else{
		query(root*2,s,tree[root].mid());
		query(root*2+1,tree[root].mid()+1,e);
	}
}
int main(){
	int N,Q;
	while(~scanf("%d %d",&N,&Q)){
		build(1,1,N);
		for(int i=1;i<=N;i++){
			scanf("%d",&num[i]);
			insert(1,i,num[i]);
		}
		int st,ed;
		for(int i=1;i<=Q;i++){
			scanf("%d %d",&st,&ed);
			minV=INF;
			maxV=-INF;
			query(1,st,ed);
			printf("%d\n",maxV-minV);
		}
	}
	return 0;
}
线段树区间更新:

http://poj.org/problem?id=3468

题意:

给定Q(1 ≤ Q≤ 100,000)个数A1,A2… AQ,,以及可能多次进行的两个操作:
1)对某个区间Ai … Aj的每个数都加n(n可变)2) 求某个区间Ai … Aj的数的和

#include<stdio.h>
#include<algorithm>
#define MAX 200009
#define INF 0xffffff0
#define LL long long int
using namespace std;
LL num[MAX],cnt=0;
struct Node{
	LL L;
	LL R;
	Node *pL;
	Node *pR;
	LL sum;
	LL add;
}tree[MAX];
LL mid(struct Node *root){
	return (root->L+root->R)/2;
}
void build(struct Node *root,int L,int R){
	root->L=L;
	root->R=R;
	root->sum=0;
	root->add=0;
	if(L==R) return;
	LL midd=(L+R)/2;
	cnt++;
	root->pL=tree+cnt;
	build(root->pL,L,midd);
	cnt++;
	root->pR=tree+cnt;
	build(root->pR,midd+1,R);
}
void insert(struct Node *root, int pos, int val){
	if(root->L==root->R){
		root->sum=val;
		return; 
	} 
	root->sum+=val;
	LL midd=mid(root);
	if(pos<=midd)insert(root->pL, pos, val);
	else insert(root->pR, pos, val);
}
void add(struct Node *root, LL L, LL R, LL val){
	if(root->L==L&&root->R==R){
		root->add+=val;
		return; 
	}
	root->sum+=(R-L+1)*val;
	LL midd=mid(root);
	if(R<=midd)add(root->pL, L, R, val);
	else if(L>midd) add(root->pR, L, R, val);
	else {
		add(root->pL, L, mid(root), val);
		add(root->pR, mid(root)+1, R,val);
	}
}
LL query(struct Node *root, LL L, LL R){
	if(root->L==L&&root->R==R){
		return root->sum+(R-L+1)*root->add;
	}
	LL midd=mid(root);
	root->sum+=(root->R-root->L+1)*root->add; 
	add(root->pL, root->L, midd, root->add);
	add(root->pR, midd+1, root->R, root->add);
	root->add=0;
	if(R<=midd) return query(root->pL, L, R);
	else if(L>midd) return query(root->pR, L, R);
	else return query(root->pL, L, midd)+query(root->pR, midd+1, R);
}
int main(){
	LL N,Q;
	while(~scanf("%I64d %I64d",&N,&Q)){
		cnt=0; 
		build(tree,1,N);
		for(int i=1;i<=N;i++){
			scanf("%I64d",&num[i]);
			insert(tree,i,num[i]);
		}
		char str[10];
		for(int i=1;i<=Q;i++){
			scanf("%s",str);
			if(str[0]=='Q'){
				LL a,b;
				scanf("%I64d %I64d",&a,&b);
				LL ans=query(tree,a,b);
				printf("%I64d\n",ans);
			}else{
				LL a,b,c;
				scanf("%I64d %I64d %I64d",&a,&b,&c);
				add(tree,a,b,c);
			}
		}
	}
	return 0;
}

这题这样写的效率更高些:

#include <cstdio>  
#define LL __int64  
  
const int N = 500010;  
LL num[N], t;  
struct node{  
    int left, right;  
    LL sum, add;  
}arr[N];  
  
void pushDown(int idx){  
    LL tmp = arr[idx].add;  
    int l = idx << 1, r = (idx << 1) ^ 1;  
    arr[l].add += tmp;  
    arr[l].sum += (arr[l].right - arr[l].left + 1) * tmp;  
    arr[r].add += tmp;  
    arr[r].sum += (arr[r].right - arr[r].left + 1) * tmp;  
    arr[idx].add = 0;  
}  
  
void build(int idx, int l, int r){  
    arr[idx].left = l, arr[idx].right = r;  
    arr[idx].add = 0;  
    if(l == r){  
        arr[idx].sum = num[l];  
        return ;  
    }  
    int mid = (l + r) >> 1;  
    build(idx * 2, l, mid);  
    build(idx * 2 + 1, mid + 1, r);  
    arr[idx].sum = arr[idx * 2].sum + arr[idx * 2 + 1].sum;  
}  
  
void update(int idx, int l, int r, int val){  
    if(arr[idx].right < l||arr[idx].left > r)  
        return ;  
    if(arr[idx].left >= l&&arr[idx].right <= r){  
        arr[idx].sum += (arr[idx].right - arr[idx].left + 1) * val;  
        arr[idx].add += val;  
        return ;  
    }  
    if(arr[idx].add != 0)  
        pushDown(idx);  
    update(idx * 2, l, r, val);  
    update(idx * 2 + 1, l, r, val);  
    arr[idx].sum = arr[idx * 2].sum + arr[idx * 2 + 1].sum;  
}  
  
LL query(int idx, int l, int r){  
    if(arr[idx].right < l||arr[idx].left > r)  
        return 0;  
    if(arr[idx].left >= l&&arr[idx].right <= r)  
        return arr[idx].sum;  
    if(arr[idx].add != 0)  
        pushDown(idx);  
    LL x = query(idx * 2, l, r);  
    LL y = query(idx * 2 + 1, l, r);  
    return x + y;  
}  
  
int main(){  
    int n, i, q, l, r;  
    char ord;  
    while(~scanf("%d%d", &n, &q)){  
        for(i = 1;i <= n;i++)  
            scanf("%lld", &num[i]);  
        build(1, 1, n);  
        while(q--){  
            scanf("\n%c", &ord);  
            if(ord == 'Q'){  
                scanf("%d%d", &l, &r);  
                printf("%lld\n", query(1, l, r));  
            } else {  
                scanf("%d%d%lld", &l, &r, &t);  
                update(1, l, r, t);  
            }  
        }  
    }  
    return 0;  
}  



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值