线段树学习总结

本篇博客会持续跟新。。。。。

线段树

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];
}

线段树的区间更新后面更新。。。。。。。

 

 

杭电习题陪练线段树

1.I Hate It

线段树的单点更新和求区间最大值

#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);
			}
		}
	}
}

2.敌兵布阵

线段树的单点更新和求区间和

#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;
		}
	}
}

3.Minimum Inversion Number

线段树的单点更新和求区间和

#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;
	}
}

4.Billboard

线段树的单点更新和求区间最大值

#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;
}

 1.Just a Hook

线段树的区间修改和区间求和

#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);
		}
	}
}

poj2528 Mayor’s posters

题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报
思路:这题数据范围很大,直接搞超时+超内存,需要离散化:
离散化简单的来说就是只取我们需要的值来用,比如说区间[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;
	}
}

  

posted @ 2015-03-04 15:01  闪光阳  阅读(213)  评论(0编辑  收藏  举报