poj 两道简单线段树 3264 && 3468
2016-08-03 19:46
239 查看
3264
http://poj.org/problem?id=3264
Balanced Lineup
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 ≤
A ≤ B ≤ N), 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
Sample Output
分析:裸的线段树和st的题,给你一个序列然后区间询问
给出三段代码:
第一段:st算法
第二段:线段树的数组实现
第三段:线段树的指针实现:
前两段效率都比较高,3000+ms的样子。第三段不知道为何4700ms,也懒得优化了
3468
http://poj.org/problem?id=3468
A Simple Problem with Integers
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
Sample Output
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!
代码:
http://poj.org/problem?id=3264
Balanced Lineup
Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 46287 | Accepted: 21709 | |
Case Time Limit: 2000MS |
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 ≤
A ≤ B ≤ N), 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 [20]; int a ; 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 ; 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 |
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 ; 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; }
相关文章推荐
- POJ 1061 && POJ 2142 两道扩展欧几里得简单题
- POJ 1573 && hdu 1035 Robot Motion【简单模拟】
- poj 3468 A Simple Problem with Integers 区间更新与询问 Splay简单应用
- poj 1103 & zoj 1142 Maze (图形模拟+简单搜索)
- 简单区间dp(nyoj 746 && poj 2955)
- POJ 1562 && ZOJ 1709 Oil Deposits(简单DFS)
- POJ 3468 A Simple Problem with Integers Splay tree&Segment tree
- HDU 2818&&POJ 1988 并查集简单应用
- poj 1658 简单的Havel-H…
- poj 1300 简单的欧拉图…
- HDU 4823 &&HDU 4826 百度之星资格赛的两道简单题。。。
- POJ 1573 && hdu 1035 Robot Motion(简单模拟)
- poj 2229&wustoj 1269划分数(简单dp)
- POJ 2006 Litmus Test (简单数学&弱酸的电离常数)
- poj 3207 简单的2-SAT问题
- poj 2387 简单的dijkstra运用
- POJ 1573 && hdu 1035(简单模拟)
- poj 2892 && 3468
- poj 2031 简单的kruskal算法运用
- 更新段&nbsp;POJ-3468-A&nbsp;Simple&nbsp;Problem…