1.详细学习
https://www.cnblogs.com/jason2003/p/9676729.html
这个博客写的很详细。
https://blog.csdn.net/iwts_24/article/details/81484561
还有这个。
2.题目1
H - 线段树各种基础操作 POJ - 3468
A Simple Problem with Integers
Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 174351 Accepted: 53649
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.
题目大意:给定N个数字,然后Q个操作
其中“Q a b”意味着区间(a,b)的所有数字之和,“C a b c” 意味着区间(a,b)中的所有数字都加上c。
模版题:
#include <iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
#define LL long long
const int maxn = 100020;
const int inf = 1000000021;
struct Node{
int a, l, r, st;
int mid(){
return (l+r)>>1;
}
}tree[maxn*4];
void pushup(int i)
{
tree[i].a = min(tree[i<<1].a, tree[i<<1|1].a);
tree[i].st = tree[i<<1].st|tree[i<<1|1].st;
}
void initTree( int i,int l , int r)
{
tree[i].l = l;
tree[i].r = r;
if(l == r)
{
scanf("%d",&tree[i].a);
tree[i].st = tree[i].a;
return;
}
int mid = tree[i].mid();
initTree(i<<1,l,mid);
initTree(i<<1|1,mid+1,r);
pushup(i);
}
void update(int i, int l , int r, int x)
{
if( l <= tree[i].l && r>= tree[i].r)
{
int t = tree[i].st & x;
if(t == tree[i].st) return ;
}
if(tree[i].l == tree[i].r)
{
tree[i].a = tree[i].a & x;
tree[i].st = tree[i].a;
return ;
}
int mid = tree[i].mid();
if(l <= mid) update(i<<1,l ,r,x);
if(r>mid)update(i<<1|1,l,r,x);
pushup(i);
}
int query(int i , int l , int r)
{
if(l <= tree[i].l && r >= tree[i].r)
return tree[i].a;
int mid = tree[i].mid();
int ans = inf;
if(l <= mid) ans = min(ans,query(i<<1, l , r));
if(r>mid) ans = min(ans,query(i<<1|1, l ,r ));
return ans;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
initTree(1,1,n);
while(m--)
{
int x, l ,r,q ;
scanf("%d",&x);
if(x)
{
scanf("%d%d%d",&l,&r,&q);
update(1,l,r,q);
}
else
{
int l ,r ;
scanf("%d%d",&l,&r);
printf("%d\n",query(1,l,r));
}
}
return 0;
}
2.题目2
这题不是很懂
J - 线段树/学会分析每个数值最多被修改的次数
You are given an array of N integers. You should support the following queries on this array.
0 L R : Find the minimum integer in the range AL, AL+1, …, AR.
1 L R X : You should apply the assignment A[i] = A[i] & X, for all indices i in range [L, R], where & denotes bitwise AND operation.
Input
First line of the input contains two space separated integers N and Q.
Second line contains N integer numbers denoting array A.
In the next Q lines, each contain one of the queries described above.
Output
For each query of the type 0, output a single line containing the answer of the query.
Constraints
1 ≤ N, Q ≤ 105
1 ≤ Ai, X ≤ 109
1 ≤ L ≤ R ≤ N
Example
Input:
5 5
1 5 2 3 4
0 2 5
1 1 5 6
0 2 2
1 2 5 3
0 1 3
Output:
2
4
0
题目大意:0 开头输出区间中的最小值,1开头进行A[i] = A[i] & X操作。
线段树的问题
#include <iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
#define LL long long
const int maxn = 100020;
const int inf = 1000000021;
struct Node{
int a, l, r, st;
int mid(){
return (l+r)>>1;
}
}tree[maxn*4];
void pushup(int i)
{
tree[i].a = min(tree[i<<1].a, tree[i<<1|1].a);
tree[i].st = tree[i<<1].st|tree[i<<1|1].st;
}
void initTree( int i,int l , int r)
{
tree[i].l = l;
tree[i].r = r;
if(l == r)
{
scanf("%d",&tree[i].a);
tree[i].st = tree[i].a;
return;
}
int mid = tree[i].mid();
initTree(i<<1,l,mid);
initTree(i<<1|1,mid+1,r);
pushup(i);
}
void update(int i, int l , int r, int x)
{
if( l <= tree[i].l && r>= tree[i].r)
{
int t = tree[i].st & x;
if(t == tree[i].st) return ;
}
if(tree[i].l == tree[i].r)
{
tree[i].a = tree[i].a & x;
tree[i].st = tree[i].a;
return ;
}
int mid = tree[i].mid();
if(l <= mid) update(i<<1,l ,r,x);
if(r>mid)update(i<<1|1,l,r,x);
pushup(i);
}
int query(int i , int l , int r)
{
if(l <= tree[i].l && r >= tree[i].r)
return tree[i].a;
int mid = tree[i].mid();
int ans = inf;
if(l <= mid) ans = min(ans,query(i<<1, l , r));
if(r>mid) ans = min(ans,query(i<<1|1, l ,r ));
return ans;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
initTree(1,1,n);
while(m--)
{
int x, l ,r,q ;
scanf("%d",&x);
if(x)
{
scanf("%d%d%d",&l,&r,&q);
update(1,l,r,q);
}
else
{
int l ,r ;
scanf("%d%d",&l,&r);
printf("%d\n",query(1,l,r));
}
}
return 0;
}
2.题目3
I - 线段树+扫描线求面积并 HDU - 1542
There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.
Input
The input file consists of several test cases. Each test case starts with a line containing a single integer n (1<=n<=100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0<=x1<x2<=100000;0<=y1<y2<=100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area.
The input file is terminated by a line containing a single 0. Don’t process it.
Output
For each test case, your program should output one section. The first line of each section must be “Test case #k”, where k is the number of the test case (starting with 1). The second one must be “Total explored area: a”, where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point.
Output a blank line after each test case.
Sample Input
2
10 10 20 20
15 15 25 25.5
0
Sample Output
Test case #1
Total explored area: 180.00
题目大意:给你几个矩形的左下角和右上角,求出这几个矩形的面积,重复部分只算一次。
解题思路:用到扫描线这个东西比较特殊,借鉴博客
https://blog.csdn.net/Merry_hj/article/details/77100290
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
using namespace std;
struct Line{
//扫描线
double x, y_up, y_down;
int flag;
}line[220];
bool cmp(Line a, Line b)
{
return a.x < b.x;
}
double y[220];
double x1,y1,x2,y2;
int n, index = 0;
struct Tree
{
double x,y_up,y_down;
bool flag ;
int cover;
}tree[1000*110];
void build(int i , int l , int r)
{
tree[i].x = 0; //这个结点上一条的x的值
tree[i].cover = 0; //该区间有多少条线段;左边线段加进去则进行++,右边线段啊加进去则--
tree[i].y_down = y[l];
tree[i].y_up = y[r];
tree[i].flag = false;
if(l+1 == r)
{
tree[i].flag = true;
return ;
}
int mid = (l+r)>>1;
build(2*i, l, mid);
build(2*i+1, mid, r);
}
double Insert(int i, double x,double l, double r, int flag )
{
if(r <= tree[i].y_down || l >= tree[i].y_up) return 0;
if(tree[i].flag)
{
if(tree[i].cover > 0)
{
double temp_x = tree[i].x;
double ans = (x - temp_x) *(tree[i].y_up - tree[i].y_down);
tree[i].x = x;
tree[i].cover += flag;
return ans;
}
else
{
tree[i].cover += flag;
tree[i].x = x;
return 0;
}
}
double ans1, ans2;
ans1 = Insert(2*i, x, l, r, flag);
ans2 = Insert(2*i+1,x,l,r,flag);
return ans1+ans2;
}
int main()
{
int casenum =1;
while(scanf("%d",&n),n)
{
index = 1;
for(int i = 1; i<=n; i++)
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
y[index] = y1;
line[index].x= x1;
line[index].y_down = y1;
line[index].flag = 1;
line[index++].y_up = y2;
y[index] = y2;
line[index].x = x2;
line[index].y_down = y1;
line[index].y_up = y2;
line[index].flag = -1;
index++;
}
sort(y+1,y+index);
sort(line+1,line+index,cmp);
build(1,1,index-1);
double ans = 0;
for(int i = 1; i<index; i++)
{
ans += Insert(1,line[i].x, line[i].y_down,line[i].y_up,line[i].flag);
}
printf("Test case #%d\nTotal explored area: %.2f\n\n",casenum++,ans);
}
return 0;
}