线段树学习总结
本篇博客会持续跟新。。。。。
线段树
1.概念
线段树是一种完全二叉树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间分别对应着线段树中的一个叶节点。主要用于区间的动态查询问题,每次操作的复杂度为O(logn)。
2.性质
如果父亲节点表示区间[a,b],那么左儿子表示的区间为[a,(a + b) / 2],右儿子[(a + b) / 2 + 1,b]。
3.用途
线段树适用于和区间统计有关的问题,比如某些数据可以按照区间进行划分,按区间动态进行修改,而且还需要按区间多次进行查询,那么使用线段树可以达到较快的查询速度。
线段树的构造
因为线段树是完全二叉树,我们可以用数组表示 Tree[MAXN]表示,那么MAXN的范围应该是多少呢?如果array[N]有N个元素,看下面代码:
int dfs(int n) {
if (n == 1) return 3;
else {
return 1 + dfs(n >> 1) + dfs(n - (n >> 1));
}
}
所以,MAXN = 4 * N - 1;
int Tree[MAXN * 4 + 10]; // 存贮最小的值得下标
int Array[MAXN];
void Bulid(int node,int left,int right) {
if (left == right) Tree[node] = left;
else {
Bulid(node << 1,left,(left + right) >> 1);
Bulid(node << 1 | 1,((left + right) >> 1) + 1,right);
Tree[node] = Array[Tree[node << 1]] <= Array[Tree[node << 1 | 1]] ? Tree[node << 1]:Tree[node << 1 | 1];
}
}
int main() {
Array[0] = 1, Array[1] = 2,Array[2] = 2, Array[3] = 4, Array[4] = 1, Array[5] = 3;
Bulid(1,0,5);
REP_1(i,4 * 5) {
cout << Tree[i] << endl;
}
}
线段树的区间查询
// [L,R]为要查询的区间
int Query(int L,int R,int node,int left,int right) {
if (R < left || L > right) return -1;
if (L <= left && right <= R) return Tree[node];
int min1 = Query(L,R,node << 1,left,(left + right) >> 1);
int min2 = Query(L,R,node << 1 | 1,((left + right) >> 1) + 1,right);
if (min1 == -1) return min2;
if (min2 == -1) return min1;
return min(min1,min2);
}
线段树的单节点更新
void Updata(int node,int left,int right,int pos,int value) {
if (left == right) {
Array[Tree[node]] = value;
return;
}
int mid = (left + right) >> 1;
if (pos <= mid) Updata(node << 1,left,mid,pos,value);
else Updata(node << 1 | 1,mid + 1,right,pos,value);
Tree[node] = Array[Tree[node << 1]] <= Array[Tree[node << 1 | 1]] ? Tree[node << 1]:Tree[node << 1 | 1];
}
线段树的区间更新后面更新。。。。。。。
杭电习题陪练线段树
线段树的单点更新和求区间最大值
#include <map>
#include <set>
#include <list>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <complex>
#include <cstring>
#include <iostream>
#include <algorithm>
#define REP(i,N) for (int i = 0;i < (N);i++)
#define REP_1(i,N) for (int i = 1;i < (N);i++)
#define REP_2(i,be,en) for (int i = (be);i < (en);i++)
#define DWN(i,N) for (int i = (N);i >= 0;i--)
#define DWN_1(i,N) for (int i = (N);i >= 1;i--)
#define DWN_2(i,en,be) for (int i = (en);i >= (be);i--)
#define FR(N) freopen((N),"r",stdin)
#define FW(N) freopen((N),"w",stdout)
#define GETS(ch) fgets((ch),MAXN,stdin)
#define INF 0x3f3f3f3f
#define MAXN 200000 * 4 + 10
#define MOD 1000000007
using namespace std;
typedef long long LL;
typedef map<char,int> MINT;
typedef vector<int> VINT;
typedef set<char> SINT;
int Array[MAXN];
void Build(int node,int left,int right) {
if (left == right) {
scanf("%d",&Array[node]);
}
else {
Build(node << 1,left,(right + left) >> 1);
Build(node << 1 | 1,((left + right) >> 1) + 1,right);
Array[node] = max(Array[node << 1],Array[node << 1 | 1]);
}
}
int Query(int L,int R,int node,int left,int right) {
if (L <= left && right <= R) {
return Array[node];
}
else {
int ans = 0;
int mid = (left + right) >> 1;
if (L <= mid) ans = max(ans,Query(L,R,node << 1,left,mid));
if (R > mid) ans = max(ans,Query(L,R,node << 1 | 1,mid + 1,right));
return ans;
}
}
void Updata(int node,int left,int right,int pos,int value) {
if (left == right) {
Array[node] = value;
}else {
int mid = (right + left) >> 1;
if (pos <= mid) Updata(node << 1,left,mid,pos,value);
else Updata(node << 1 | 1,mid + 1,right,pos,value);
Array[node] = max(Array[node << 1],Array[node << 1 | 1]);
}
}
int main () {
int N,M;
//FR("1.txt");
while (~scanf("%d%d",&N,&M)) {
Build(1,1,N);
REP(i,M) {
char ch[2];
int A,B;
scanf("%s%d%d",&ch,&A,&B);
if (ch[0] == 'Q') {
cout << Query(A,B,1,1,N) << endl;
}
else {
Updata(1,1,N,A,B);
}
}
}
}
线段树的单点更新和求区间和
#include <map>
#include <set>
#include <list>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <complex>
#include <cstring>
#include <iostream>
#include <algorithm>
#define REP(i,N) for (int i = 0;i < (N);i++)
#define REP_1(i,N) for (int i = 1;i < (N);i++)
#define REP_2(i,be,en) for (int i = (be);i < (en);i++)
#define DWN(i,N) for (int i = (N);i >= 0;i--)
#define DWN_1(i,N) for (int i = (N);i >= 1;i--)
#define DWN_2(i,en,be) for (int i = (en);i >= (be);i--)
#define FR(N) freopen((N),"r",stdin)
#define FW(N) freopen((N),"w",stdout)
#define GETS(ch) fgets((ch),MAXN,stdin)
#define INF 0x3f3f3f3f
#define MAXN 50000 * 4 + 10
#define MOD 1000000007
using namespace std;
typedef long long LL;
typedef map<char,int> MINT;
typedef vector<int> VINT;
typedef set<char> SINT;
int Array[MAXN];
void Build(int node,int left,int right) {
if (left == right) {
scanf("%d",&Array[node]);
return;
}
else {
Build(node << 1,left,(right + left) >> 1);
Build(node << 1 | 1,((left + right) >> 1) + 1,right);
Array[node] = Array[node << 1] + Array[node << 1 | 1];
}
}
int Query(int node,int left,int right,int L,int R) {
if (L <= left && right <= R) {
return Array[node];
}
else {
int ans = 0;
int mid = (left + right) >> 1;
if (L <= mid) ans += Query(node << 1,left,mid,L,R);
if (R > mid) ans += Query(node << 1 | 1,mid + 1,right,L,R);
return ans;
}
}
void Updata(int node,int left,int right,int pos,int value) {
if (left == right) {
Array[node] += value;
}else {
int mid = (right + left) >> 1;
if (pos <= mid) Updata(node << 1,left,mid,pos,value);
else Updata(node << 1 | 1,mid + 1,right,pos,value);
Array[node] = Array[node << 1] + Array[node << 1 | 1];
}
}
int main () {
int N,M;
int T;
int kase = 1;
//FR("1.txt");
scanf("%d",&T);
while (T--) {
printf("Case %d:\n",kase++);
scanf("%d",&N);
Build(1,1,N);
while(1) {
char ch[10];
int A,B;
scanf("%s",ch);
if (ch[0] == 'Q') {
scanf("%d%d",&A,&B);
cout << Query(1,1,N,A,B) << endl;
}
else if (ch[0] == 'A'){
scanf("%d%d",&A,&B);
Updata(1,1,N,A,B);
}
else if (ch[0] == 'S') {
scanf("%d%d",&A,&B);
Updata(1,1,N,A,-B);
}else break;
}
}
}
线段树的单点更新和求区间和
#include <map>
#include <set>
#include <list>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <complex>
#include <cstring>
#include <iostream>
#include <algorithm>
#define REP(i,N) for (int i = 0;i < (N);i++)
#define REP_1(i,N) for (int i = 1;i < (N);i++)
#define REP_2(i,be,en) for (int i = (be);i < (en);i++)
#define DWN(i,N) for (int i = (N);i >= 0;i--)
#define DWN_1(i,N) for (int i = (N);i >= 1;i--)
#define DWN_2(i,en,be) for (int i = (en);i >= (be);i--)
#define FR(N) freopen((N),"r",stdin)
#define FW(N) freopen((N),"w",stdout)
#define GETS(ch) fgets((ch),MAXN,stdin)
#define INF 0x3f3f3f3f
#define MAXN 5000 * 4 + 10
#define MOD 1000000007
using namespace std;
typedef long long LL;
typedef map<char,int> MINT;
typedef vector<int> VINT;
typedef set<char> SINT;
int Array[MAXN];
void Build(int node,int left,int right) {
Array[node] = 0;
if (left == right) {
return;
}
else {
Build(node << 1,left,(right + left) >> 1);
Build(node << 1 | 1,((left + right) >> 1) + 1,right);
}
}
int Query(int node,int left,int right,int L,int R) {
if (L <= left && right <= R) {
return Array[node];
}
else {
int ans = 0;
int mid = (left + right) >> 1;
if (L <= mid) ans += Query(node << 1,left,mid,L,R);
if (R > mid) ans += Query(node << 1 | 1,mid + 1,right,L,R);
return ans;
}
}
void Updata(int node,int left,int right,int pos) {
if (left == right) {
Array[node]++;
}else {
int mid = (right + left) >> 1;
if (pos <= mid) Updata(node << 1,left,mid,pos);
else Updata(node << 1 | 1,mid + 1,right,pos);
Array[node] = Array[node << 1] + Array[node << 1 | 1];
}
}
int main () {
int N;
//FR("1.txt");
while (cin >> N) {
Build(1,0,N - 1);
int A[MAXN];
int sum = 0;
REP(i,N) {
cin >> A[i];
Updata(1,0,N - 1,A[i]);
if (A[i] + 1 < N)
sum += Query(1,0,N - 1,A[i] + 1,N - 1);
}
int ans = sum;
REP(i,N) {
sum += N - A[i] - A[i] - 1;
ans = min(ans,sum);
}
cout << ans << endl;
}
}
线段树的单点更新和求区间最大值
#include <map>
#include <set>
#include <list>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <complex>
#include <cstring>
#include <iostream>
#include <algorithm>
#define REP(i,N) for (int i = 0;i < (N);i++)
#define REP_1(i,N) for (int i = 1;i < (N);i++)
#define REP_2(i,be,en) for (int i = (be);i < (en);i++)
#define DWN(i,N) for (int i = (N);i >= 0;i--)
#define DWN_1(i,N) for (int i = (N);i >= 1;i--)
#define DWN_2(i,en,be) for (int i = (en);i >= (be);i--)
#define FR(N) freopen((N),"r",stdin)
#define FW(N) freopen((N),"w",stdout)
#define GETS(ch) fgets((ch),MAXN,stdin)
#define INF 0x3f3f3f3f
#define MAXN 200000 * 4 + 10
#define MOD 1000000007
using namespace std;
typedef long long LL;
typedef map<char,int> MINT;
typedef vector<int> VINT;
typedef set<char> SINT;
typedef pair<int,int> PINT;
int Array[MAXN];
int H,W,N;
void Build(int node,int left,int right) {
Array[node] = W;
if (left == right) {
return;
}
else {
Build(node << 1,left,(right + left) >> 1);
Build(node << 1 | 1,((left + right) >> 1) + 1,right);
}
}
int Query(int node,int left,int right,int x) {
if (left == right) {
Array[node] -= x;
return left;
}
else {
int mid = (left + right) >> 1;
int ans;
if (Array[node << 1] >= x) {
ans = Query(node << 1,left,mid,x);
}
else ans = Query(node << 1 | 1,mid + 1,right,x);
Array[node] = max(Array[node << 1],Array[node << 1 | 1]);
return ans;
}
}
int main () {
//FR("1.txt");
while (~scanf("%d%d%d",&H,&W,&N)) {
H = min(H,N);
Build(1,1,H);
while (N--){
int x;
scanf("%d",&x);
if (Array[1] < x) {
cout << -1 << endl;
}
else {
cout << Query(1,1,H,x) << endl;
}
}
}
}
线段树的区间更新
需要用到延迟标记,每个节点新增加一个标记,记录这个节点是否被进行了某种修改操作(会影响到子孙节点)。我们先按照查询的方式将其划分成线段树中的节点,然后修改这些节点的信息,并给这些节点标上标记,在修改和查询的时候,如果我们到了一个节点p,并且决定考虑其子节点,那么我们就要看看节点p有没有标记,如果有,就要按照标记修改其子节点的信息,并且给子节点都标上相同的标记,同时消掉p的标记。模板:
LL add[MAXN << 2];
LL sum[MAXN << 2];
void PushDown(int node,int num) {
if (add[node]) {
add[node << 1] += add[node];
add[node << 1 | 1] += add[node];
sum[node << 1] += add[node] * (num - (num >> 1));
sum[node << 1 | 1] += add[node] * (num >> 1);
add[node] = 0;
}
}
void Build(int node,int left,int right) {
add[node] = 0;
if (left == right) {
scanf("%I64d",&sum[node]);
return;
}
else {
int mid = (left + right) >> 1;
Build(node << 1,left,mid);
Build(node << 1 | 1, mid + 1,right);
sum[node] = sum[node << 1] + sum[node << 1 | 1];
}
}
void Updata(int node,int left,int right,int L,int R,int value) {
if (L <= left && right <= R) {
add[node] += value;
sum[node] += (LL)value * (right - left + 1);
return;
}
else {
PushDown(node,right - left + 1);
int mid = (left + right) >> 1;
if (L <= mid) Updata(node << 1,left,mid,L,R,value);
if (R > mid) Updata(node << 1 | 1,mid + 1,right,L,R,value);
sum[node] = sum[node << 1] + sum[node << 1 | 1];
}
}
LL Query(int node,int left,int right,int L,int R) {
if (L <= left && right <= R) {
return sum[node];
}
PushDown(node,right - left + 1);
int mid = (left + right) >> 1;
LL ans = 0;
if (L <= mid) ans += Query(node << 1,left,mid,L,R);
if (mid < R) ans += Query(node << 1 | 1,mid + 1,right,L,R);
return ans;
}
线段树的区间修改和区间求和
#include <map>
#include <set>
#include <list>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <complex>
#include <cstring>
#include <iostream>
#include <algorithm>
#define REP(i,N) for (int i = 0;i < (N);i++)
#define REP_1(i,N) for (int i = 1;i < (N);i++)
#define REP_2(i,be,en) for (int i = (be);i < (en);i++)
#define DWN(i,N) for (int i = (N);i >= 0;i--)
#define DWN_1(i,N) for (int i = (N);i >= 1;i--)
#define DWN_2(i,en,be) for (int i = (en);i >= (be);i--)
#define FR(N) freopen((N),"r",stdin)
#define FW(N) freopen((N),"w",stdout)
#define GETS(ch) fgets((ch),MAXN,stdin)
#define INF 0x3f3f3f3f
#define MAXN 100010
#define MOD 1000000007
using namespace std;
typedef long long LL;
typedef map<char,int> MINT;
typedef vector<int> VINT;
typedef set<char> SINT;
typedef pair<int,int> PINT;
LL add[MAXN << 2];
LL sum[MAXN << 2];
void PushDown(int node,int num) {
if (add[node]) {
add[node << 1] = add[node];
add[node << 1 | 1] = add[node];
sum[node << 1] = add[node] * (num - (num >> 1));
sum[node << 1 | 1] = add[node] * (num >> 1);
add[node] = 0;
}
}
void Build(int node,int left,int right) {
add[node] = 0;
sum[node] = 1;
if (left == right) {
return;
}
else {
int mid = (left + right) >> 1;
Build(node << 1,left,mid);
Build(node << 1 | 1, mid + 1,right);
sum[node] = sum[node << 1] + sum[node << 1 | 1];
}
}
void Updata(int node,int left,int right,int L,int R,int value) {
if (L <= left && right <= R) {
add[node] = value;
sum[node] = (LL)value * (right - left + 1);
return;
}
else {
PushDown(node,right - left + 1);
int mid = (left + right) >> 1;
if (L <= mid) Updata(node << 1,left,mid,L,R,value);
if (R > mid) Updata(node << 1 | 1,mid + 1,right,L,R,value);
sum[node] = sum[node << 1] + sum[node << 1 | 1];
}
}
LL Query(int node,int left,int right,int L,int R) {
if (L <= left && right <= R) {
return sum[node];
}
PushDown(node,right - left + 1);
int mid = (left + right) >> 1;
LL ans = 0;
if (L <= mid) ans += Query(node << 1,left,mid,L,R);
if (mid < R) ans += Query(node << 1 | 1,mid + 1,right,L,R);
return ans;
}
int main () {
int T,N,M;
//FR("1.txt");
cin >> T;
int cas = 1;
while (T--) {
scanf("%d%d",&N,&M);
Build(1,1,N);
REP(i,M) {
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
Updata(1,1,N,a,b,c);
}
printf("Case %d: The total value of the hook is %I64d.\n",cas++ , sum[1]);
}
}
2.A Simple Problem with Integers
线段树的区间修改和区间求和
#include <map>
#include <set>
#include <list>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <complex>
#include <cstring>
#include <iostream>
#include <algorithm>
#define REP(i,N) for (int i = 0;i < (N);i++)
#define REP_1(i,N) for (int i = 1;i < (N);i++)
#define REP_2(i,be,en) for (int i = (be);i < (en);i++)
#define DWN(i,N) for (int i = (N);i >= 0;i--)
#define DWN_1(i,N) for (int i = (N);i >= 1;i--)
#define DWN_2(i,en,be) for (int i = (en);i >= (be);i--)
#define FR(N) freopen((N),"r",stdin)
#define FW(N) freopen((N),"w",stdout)
#define GETS(ch) fgets((ch),MAXN,stdin)
#define INF 0x3f3f3f3f
#define MAXN 100010
#define MOD 1000000007
using namespace std;
typedef long long LL;
typedef map<char,int> MINT;
typedef vector<int> VINT;
typedef set<char> SINT;
typedef pair<int,int> PINT;
LL add[MAXN << 2];
LL sum[MAXN << 2];
void PushDown(int node,int num) {
if (add[node]) {
add[node << 1] += add[node];
add[node << 1 | 1] += add[node];
sum[node << 1] += add[node] * (num - (num >> 1));
sum[node << 1 | 1] += add[node] * (num >> 1);
add[node] = 0;
}
}
void Build(int node,int left,int right) {
add[node] = 0;
if (left == right) {
scanf("%I64d",&sum[node]);
return;
}
else {
int mid = (left + right) >> 1;
Build(node << 1,left,mid);
Build(node << 1 | 1, mid + 1,right);
sum[node] = sum[node << 1] + sum[node << 1 | 1];
}
}
void Updata(int node,int left,int right,int L,int R,int value) {
if (L <= left && right <= R) {
add[node] += value;
sum[node] += (LL)value * (right - left + 1);
return;
}
else {
PushDown(node,right - left + 1);
int mid = (left + right) >> 1;
if (L <= mid) Updata(node << 1,left,mid,L,R,value);
if (R > mid) Updata(node << 1 | 1,mid + 1,right,L,R,value);
sum[node] = sum[node << 1] + sum[node << 1 | 1];
}
}
LL Query(int node,int left,int right,int L,int R) {
if (L <= left && right <= R) {
return sum[node];
}
PushDown(node,right - left + 1);
int mid = (left + right) >> 1;
LL ans = 0;
if (L <= mid) ans += Query(node << 1,left,mid,L,R);
if (mid < R) ans += Query(node << 1 | 1,mid + 1,right,L,R);
return ans;
}
int main () {
int N,Q;
//FR("1.txt");
cin >> N >> Q;
Build(1,1,N);
while (Q--) {
char ch[2];
int a,b,c;
scanf("%s%d%d",ch,&a,&b);
if (ch[0] == 'Q') {
printf("%I64d\n",Query(1,1,N,a,b));
}
else {
scanf("%d",&c);
Updata(1,1,N,a,b,c);
}
}
}
题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报
思路:这题数据范围很大,直接搞超时+超内存,需要离散化:
离散化简单的来说就是只取我们需要的值来用,比如说区间[1000,2000],[1990,2012] 我们用不到[-∞,999][1001,1989][1991,1999][2001,2011][2013,+∞]这些值,所以我只需要1000,1990,2000,2012就够了,将其分别映射到0,1,2,3,在于复杂度就大大的降下来了
所以离散化要保存所有需要用到的值,排序后,分别映射到1~n,这样复杂度就会小很多很多
而这题的难点在于每个数字其实表示的是一个单位长度(并非一个点),这样普通的离散化会造成许多错误(包括我以前的代码,poj这题数据奇弱)
给出下面两个简单的例子应该能体现普通离散化的缺陷:
例子一:1-10 1-4 5-10
例子二:1-10 1-4 6-10
普通离散化后都变成了[1,4][1,2][3,4]
线段2覆盖了[1,2],线段3覆盖了[3,4],那么线段1是否被完全覆盖掉了呢?
例子一是完全被覆盖掉了,而例子二没有被覆盖
为了解决这种缺陷,我们可以在排序后的数组上加些处理,比如说[1,2,6,10]
如果相邻数字间距大于1的话,在其中加上任意一个数字,比如加成[1,2,3,6,7,10],然后再做线段树就好了.
线段树功能:update:成段替换 query:简单hash
#include <map>
#include <set>
#include <list>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <complex>
#include <cstring>
#include <iostream>
#include <algorithm>
#define REP(i,N) for (int i = 0;i < (N);i++)
#define REP_1(i,N) for (int i = 1;i < (N);i++)
#define REP_2(i,be,en) for (int i = (be);i < (en);i++)
#define DWN(i,N) for (int i = (N);i >= 0;i--)
#define DWN_1(i,N) for (int i = (N);i >= 1;i--)
#define DWN_2(i,en,be) for (int i = (en);i >= (be);i--)
#define FR(N) freopen((N),"r",stdin)
#define FW(N) freopen((N),"w",stdout)
#define GETS(ch) fgets((ch),MAXN,stdin)
#define INF 0x3f3f3f3f
#define MAXN 40010
#define MOD 1000000007
using namespace std;
typedef long long LL;
typedef map<char,int> MINT;
typedef vector<int> VINT;
typedef set<int> SINT;
typedef pair<int,int> PINT;
int color[MAXN << 2];
class Node {
public:
int be,en;
}X[MAXN];
int Array[MAXN];
int Hash[MAXN];
int ans = 0;
void Build(int node,int left,int right) {
color[node] = -1;
if (left == right) return;
int mid = (left + right) >> 1;
Build(node << 1,left,mid);
Build(node << 1 | 1,mid + 1,right);
}
void PushDown(int node) {
if (color[node] != -1) {
color[node << 1] = color[node << 1 | 1] = color[node];
color[node] = -1;
}
}
void Updata(int node,int left,int right,int L,int R,int value) {
if (L <= left && right <= R) {
color[node] = value;
return;
}
PushDown(node);
int mid = (left + right) >> 1;
if (L <= mid) Updata(node << 1,left,mid,L,R,value);
if (R > mid) Updata(node << 1 | 1,mid + 1,right,L,R,value);
}
void Query(int node,int left,int right) {
if (color[node] != -1) {
if (!Hash[color[node]]) {
Hash[color[node]] = 1;
ans++;
}
return;
}
if (left == right) return;
int mid = (right + left) >> 1;
Query(node << 1,left,mid);
Query(node << 1 | 1,mid + 1,right);
}
int main () {
int T;
//FR("1.txt");
cin >> T;
while (T--) {
int N;
cin >> N;
int num = 0;
REP(i,N) {
scanf("%d %d",&X[i].be,&X[i].en);
Array[num++] = X[i].be;
Array[num++] = X[i].en;
}
sort(Array,Array + num);
num = unique(Array,Array + num) - Array;
DWN_2(i,num - 1,1) {
if (Array[i] - Array[i - 1] != 1) {
Array[num++] = Array[i - 1] + 1;
}
}
sort(Array,Array + num);
Build(1,0,num - 1);
REP(i,N) {
int be = lower_bound(Array,Array + num,X[i].be) - Array;
int en = lower_bound(Array,Array + num,X[i].en) - Array;
Updata(1,0,num - 1,be,en,i);
}
memset(Hash,0,sizeof(Hash));
ans = 0;
Query(1,0,num - 1);
cout << ans << endl;
}
}

浙公网安备 33010602011771号