poj 两道简单线段树 3264 3468

2024-04-22 06:08
文章标签 简单 poj 线段 3264 两道 3468

本文主要是介绍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);
#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

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和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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/924974

相关文章

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

hdu2289(简单二分)

虽说是简单二分,但是我还是wa死了  题意:已知圆台的体积,求高度 首先要知道圆台体积怎么求:设上下底的半径分别为r1,r2,高为h,V = PI*(r1*r1+r1*r2+r2*r2)*h/3 然后以h进行二分 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#includ

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

hdu1689(线段树成段更新)

两种操作:1、set区间[a,b]上数字为v;2、查询[ 1 , n ]上的sum 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdl

usaco 1.3 Prime Cryptarithm(简单哈希表暴搜剪枝)

思路: 1. 用一个 hash[ ] 数组存放输入的数字,令 hash[ tmp ]=1 。 2. 一个自定义函数 check( ) ,检查各位是否为输入的数字。 3. 暴搜。第一行数从 100到999,第二行数从 10到99。 4. 剪枝。 代码: /*ID: who jayLANG: C++TASK: crypt1*/#include<stdio.h>bool h

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

poj 1511 Invitation Cards(spfa最短路)

题意是给你点与点之间的距离,求来回到点1的最短路中的边权和。 因为边很大,不能用原来的dijkstra什么的,所以用spfa来做。并且注意要用long long int 来存储。 稍微改了一下学长的模板。 stack stl 实现代码: #include<stdio.h>#include<stack>using namespace std;const int M

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int