本文主要是介绍poj 两道简单线段树 3264 3468,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
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
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 ≤ A ≤ B ≤ N), representing the range of cows from A to B inclusive.
Output
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);
#endifwhile(~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 == itree[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);elseInsert(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_JUDGEfreopen("in.txt","r",stdin);
// freopen("Out.txt", "w", stdout);
#endifwhile(~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
分析:题目出了要询问[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和addtree[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_JUDGEfreopen("in.txt","r",stdin);
// freopen("Out.txt", "w", stdout);
#endifwhile(~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;
}
这篇关于poj 两道简单线段树 3264 3468的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!