poj 两道简单线段树 3264 && 3468

3264

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

Balanced Lineup
Time Limit: 5000MS
Memory Limit: 65536K
Total Submissions: 46287
Accepted: 21709
Case Time Limit: 2000MS

Description

For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John decides to organize a game of Ultimate Frisbee with some of the cows. To keep things simple, he will take a contiguous range of cows from the milking lineup to play the game. However, for all the cows to have fun they should not differ too much in height.

Farmer John has made a list of Q (1 ≤ Q ≤ 200,000) potential groups of cows and their heights (1 ≤ height ≤ 1,000,000). For each group, he wants your help to determine the difference in height between the shortest and the tallest cow in the group.

Input

Line 1: Two space-separated integers, N and Q.
Lines 2..N+1: Line i+1 contains a single integer that is the height of cow i
Lines N+2..N+Q+1: Two integers A and B (1 ≤ ABN), representing the range of cows from A to B inclusive.

Output

Lines 1..Q: Each line contains a single integer that is a response to a reply and indicates the difference in height between the tallest and shortest cow in the range.

Sample Input

6 3
1
7
3
4
2
5
1 5
4 6
2 2

Sample Output

6
3
0


分析:裸的线段树和st的题,给你一个序列然后区间询问
给出三段代码:
第一段:st算法
/*
 * rmp_st.cpp
 *
 *  Created on: 2016年3月4日
 *      Author: Triose
 */
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<map>
#include<set>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define inf 0x3f3f3f3f
#define rep(i,a) for((i)=0; i<(a);(i)++)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define LL __int64
const double PI = acos(-1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b)*b; }
template<class T> inline T Min(T a, T b) { return a < b ? a : b; }
template<class T> inline T Max(T a, T b) { return a > b ? a : b; }
int n, m;
int x, y;
#define N 50000
struct node {
	int max_num;
	int min_num;
};
node dp[N][20];
int a[N];
void Init() {
	int high = (int)log2(n * 1.0) + 1;
	for(int j = 1; j < high; j++) {
		int k = 1 << (j - 1);
		for(int i = 1; i + k <= n; i++) {
			dp[i][j].max_num = Max(dp[i][j - 1].max_num,dp[i + k][j - 1].max_num);
			dp[i][j].min_num = Min(dp[i][j - 1].min_num,dp[i + k][j - 1].min_num);
		}
	}
}
int main() {
#ifndef ONLINE_JUDGE
//	freopen("in.txt","r",stdin);
//	freopen("Out.txt", "w", stdout);
#endif
	while(~sfd(n,m)) {
		for(int i = 1; i <= n; i++) {
			sf(a[i]);
			dp[i][0].max_num = a[i];
			dp[i][0].min_num = a[i];
		}
		Init();
		for(int i = 0; i < m; i++) {
			sfd(x,y);
			int k = (int)log2(y - x + 1.0);
			pf(Max(dp[x][k].max_num,dp[y - (1 << k) + 1][k].max_num) - Min(dp[x][k].min_num,dp[y - (1 << k) + 1][k].min_num));
		}
	}
	return 0;
}

第二段:线段树的数组实现
#include <iostream>
#include <stdio.h>
using namespace std;
const int INF = 0xffffff0;
int minV = INF;
int maxV = -INF;
struct Node //不要左右子节点指针的做法
{
    int L, R;
    int minV,maxV;
    int Mid() {
    return (L+R)/2;
    }
};
Node tree[800010]; //4倍叶子节点的数量就够void BuildTree(int root , int L, int R)
void BuildTree(int root, int L, int R)
{
    tree[root].L = L;
    tree[root].R = R;
    tree[root].minV = INF;
    tree[root].maxV = - INF;
    if( L != R ) {
        BuildTree(2*root+1,L,(L+R)/2);
        BuildTree(2*root+2,(L+R)/2 + 1, R);
    }
}
void Insert(int root, int i,int v)
//将第i个数,其值为v,插入线段树
{
    if( tree[root].L == tree[root].R ) {
//成立则亦有 tree[root].R == i
        tree[root].minV = tree[root].maxV = v;
        return;
    }
    tree[root].minV = min(tree[root].minV,v);
    tree[root].maxV = max(tree[root].maxV,v);
    if( i <= tree[root].Mid() )
        Insert(2*root+1,i,v);
    else
        Insert(2*root+2,i,v);
}
void Query(int root,int s,int e) {
//查询区间[s,e]中的最小值和最大值,如果更优就记在全局变量里
//minV和maxV里
if( tree[root].minV >= minV && tree[root].maxV <= maxV )
    return;
if( tree[root].L == s && tree[root].R == e ) {
        minV = min(minV,tree[root].minV);
        maxV = max(maxV,tree[root].maxV);
        return ;
    }
    if( e <= tree[root].Mid())
        Query(2*root+1,s,e);
    else if( s > tree[root].Mid() )
        Query(2*root+2,s,e);
    else {
        Query(2*root+1,s,tree[root].Mid());
        Query(2*root+2,tree[root].Mid()+1,e);
    }
}
int main()
{
    int n,q,h;
    int i,j,k;
    scanf("%d%d",&n,&q);
    BuildTree(0,1,n);
    for( i = 1;i <= n;i ++ ) {
        scanf("%d",&h);
        Insert(0,i,h);
    }
    for( i = 0;i < q;i ++ ) {
        int s,e;
        scanf("%d%d", &s,&e);
        minV = INF;
        maxV = -INF;
        Query(0,s,e);
        printf("%d\n",maxV - minV);
    }
    return 0;
}

第三段:线段树的指针实现:
/*************************************************************************
    > File Name: p3264.cpp
    > Author: Triose
    > Mail: Triose@163.com 
    > Created Time: 2016年07月26日 星期二 08时58分17秒
 ************************************************************************/

//#include<bits/stdc++.h>
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#include<map>
#include<set>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define ds(a) int a; sf(a)
#define PR(a,b) pair<a,b>
#define fi first
#define se second
#define LL long long
#define DB double
const double PI = acos(-1.0);
const double E = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> inline T Min(T a, T b) { return a < b ? a : b; }
template<class T> inline T Max(T a, T b) { return a > b ? a : b; }
int n, m;
#define N 200010
int maxq, minq;
int a[N];
struct Elmt {
    int s, e;
    int maxn, minn;
    Elmt * left, * right;
    Elmt(int s, int e) {
	this->s = s; this->e = e;
	this->maxn = -1; this->minn = INF;
	left = NULL; right = NULL;
    }
};
Elmt * tree;
void build(Elmt * elmt) {
    if(elmt->s == elmt->e) {
	elmt->maxn = a[elmt->s];
	elmt->minn = a[elmt->e];
	return ;
    }
    else {
	int mid = (elmt->s + elmt->e) >> 1;
	if(!elmt->left)
	    elmt->left = new Elmt(elmt->s, mid);
	else {
	    elmt->left->s = elmt->s; elmt->left->e = mid;
	}
	if(!elmt->right)
	    elmt->right = new Elmt(mid + 1, elmt->e);
	else {
	    elmt->right->s = mid + 1; elmt->right->e = elmt->e;
	}
	build(elmt->left); build(elmt->right);
	elmt->maxn = Max(elmt->left->maxn, elmt->right->maxn);
	elmt->minn = Min(elmt->left->minn, elmt->right->minn);
	return ;
    }
}
void collapse(Elmt * elmt) {
    if(!elmt) return ;
    collapse(elmt->left);
    collapse(elmt->right);
    delete elmt;
    return ;
}

void query(Elmt * elmt, int s, int e) {
    if(elmt->s == s && elmt->e == e) {
	maxq = Max(elmt->maxn, maxq);
	minq = Min(elmt->minn, minq);
	return ;
    }
    int mid = (elmt->s + elmt->e) >> 1;
    if(e <= mid) {
	query(elmt->left, s, e);
    }
    else if(s > mid) {
	query(elmt->right, s, e);
    }
    else {
	query(elmt->left, s, mid);
	query(elmt->right, mid + 1, e);
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
//  freopen("Out.txt", "w", stdout);
#endif
    while(~sfd(n, m)) {
	repe(i, 1, n) sf(a[i]);
	tree = new Elmt(1, n);
	build(tree);
	int l, r;
	while(m--) {
	    sfd(l, r);
	    maxq = -1; minq = INF;
	    if(l == r) {
		pf(0);continue;
	    }
	    query(tree, l, r);
	    pf((maxq - minq));
	}
	//collapse(tree);
    }
    return 0;
}

前两段效率都比较高,3000+ms的样子。第三段不知道为何4700ms,也懒得优化了




3468

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

A Simple Problem with Integers
Time Limit: 5000MS
Memory Limit: 131072K
Total Submissions: 94413
Accepted: 29408
Case Time Limit: 2000MS

Description

You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+1, ... , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

Sample Output

4
55
9
15

Hint

The sums may exceed the range of 32-bit integers.


分析:题目出了要询问[l, r]的和之外,还有对区间[l, r]进行的加操作。如果线段树结点仅保存区间的和那么询问的复杂度为O(log n) 而操作的效率为o(n * log n) 太慢了,所以在结点里增加一个名字叫 “增量” 的变量,表示该区间每一个数要增加的大小。那么就可以实现询问和加操作的效率都是O(n logn)(每次加操作,不把值直接加到对应区间的数上面取,而是加到对应区间的增量上去,这样操作后该区间的和就为 (r - l + 1) * add) 注意维护sum 和 add!

代码:

/*************************************************************************
    > File Name: 3468.cpp
    > Author: Triose
    > Mail: Triose@163.com 
    > Created Time: 2016年08月03日 星期三 16时35分43秒
 ************************************************************************/

//#include<bits/stdc++.h>
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#include<map>
#include<set>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%lld",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%lld\n",a)
#define ds(a) int a; sf(a)
#define PR(a,b) pair<a,b>
#define fi first
#define se second
#define LL long long
#define DB double
const double PI = acos(-1.0);
const double E = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> inline T Min(T a, T b) { return a < b ? a : b; }
template<class T> inline T Max(T a, T b) { return a > b ? a : b; }
int n, m;
#define N 100010
LL a[N];
struct Elmt {
    int l, r;
    LL sum;
    LL add;
    Elmt() {
	l = 0; r = 0;
	sum = 0;
	add = 0;
    }
};
Elmt tree[N * 4];
void Build(int root, int s, int e) {
    if(s == e) {
	tree[root].l = tree[root].r = s;
	tree[root].sum = a[s]; tree[root].add = 0;
	return ;
    }
    tree[root].l = s; tree[root].r = e;
    int mid = (s + e) >> 1;
    Build(root * 2 + 1, s, mid);
    Build(root * 2 + 2, mid + 1, e);
    tree[root].sum = tree[root * 2 + 1].sum + tree[root * 2 + 2].sum;
    tree[root].add = 0;
    return ;
}
void Adto(int root, int s, int e, LL dter) {
    if(tree[root].l == s && tree[root].r == e) {
	tree[root].add += dter;
	return ;
    }
    tree[root].sum += dter * (e - s + 1);//注意维护sum!
    int mid = (tree[root].l + tree[root].r) >> 1;
    if(e <= mid) {
	Adto(root * 2 + 1, s, e, dter);
    }
    else if(s > mid) {
	Adto(root * 2 + 2, s, e, dter);
    }
    else {
	Adto(root * 2 + 1, s, mid, dter);
	Adto(root * 2 + 2, mid + 1, e, dter);
    }
}
LL Query(int root, int s, int e) {
    if(tree[root].l == s && tree[root].r == e) {
	return tree[root].sum + (tree[root].r - tree[root].l + 1) * tree[root].add;
    }//注意应该返回的是sum还是sum + add 还是 sum + len * add!
    tree[root * 2 + 1].add += tree[root].add;//把add往下带一层,更新本层的sum和add
    tree[root * 2 + 2].add += tree[root].add;
    tree[root].sum += ((tree[root].r - tree[root].l + 1) * tree[root].add);
    tree[root].add = 0;
    int mid = (tree[root].l + tree[root].r) >> 1;
    if(e <= mid) {
	return Query(root * 2 + 1, s, e);
    }
    else if(s > mid) {
	return Query(root * 2 + 2, s, e);
    }
    else {
	return Query(root * 2 + 1, s, mid) + Query(root * 2 + 2, mid + 1, e);
    }
}
char order[5];
int s, e;
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
//  freopen("Out.txt", "w", stdout);
#endif
    while(~sfd(n, m)) {
	repe(i, 1, n) sfI(a[i]);
	Build(0, 1, n);
	while(m--) {
	    scanf("%s%d%d", order, &s, &e);
	    if(order[0] == 'Q') {
		pfI(Query(0, s, e));
	    }
	    else {
		LL dter; sfI(dter);
		Adto(0, s, e, dter);
	    }
	}
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值