离散化手法:
本人现把 “实段”区间,现转换为 “端点区间” 意思 1-2的“实段” 区间对应在坐标轴上从点1到点3的一个端点区间。
然后把所有坐标加入数组排序去重,一个线段区间,总可以被分割为若干段。
如 1 - 5 2 - 3 两段,那么 数组内 1 2 4 6 那么原来的 1 - 5 段 被拆分为端点段 1 - 2 , 2 - 4,,4-6三段对应线段树上的三个连续点(本人线段树每个点代表一个实段);
正因为每个区间都能找到自己的正确拆分,则可与线段树相对应,
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <cmath> #include <map> #include <set> #include <cctype> #include <deque> using namespace std; typedef long long LL; #define rep(i,n) for(int (i)=0;(i)<(n);(i)++) #define rep1(i,n) for(int (i)=1;(i)<=(n);(i)++) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn = 51111; int col[maxn<<2]; void build(int l,int r,int rt){ col[rt] = -1; if(l==r) return ; int m = (l+r)>>1; build(lson); build(rson); } void push_down(int rt){ if(col[rt]!=-1){ col[rt<<1] = col[rt<<1|1] = col[rt]; col[rt] = -1; } } void update(int l,int r,int rt,int L,int R,int v){ if(L<=l&&r<=R){ col[rt] = v; return; } push_down(rt); int m = (l+r)>>1; if(L<=m) update(lson,L,R,v); if(R>m) update(rson,L,R,v); } int query(int l,int r,int rt,int p){ if(l==r) return col[rt]; push_down(rt); int m = (l+r)>>1; if(p<=m) return query(lson,p); else return query(rson,p); } int a[maxn<<1],cnt,vis[maxn<<1]; int find(int v){ int x = 1, y=cnt; while(x<y){ int m = (x+y)>>1; if(a[m] == v) return m; if(a[m]<v) x = m+1; else y = m; } } int x[maxn],y[maxn],n; int main() { int T; scanf("%d",&T); while(T--){ scanf("%d",&n); cnt = 1; for(int i=1;i<=n;i++){ scanf("%d %d",&x[i],&y[i]); y[i]++; a[cnt++] = x[i]; a[cnt++] = y[i]; } sort(a+1,a+cnt); int lim = cnt; cnt = 1; for(int i=1;i<lim;i++){ if(i==1 || a[i]!=a[i-1]){ a[cnt++] = a[i]; } } build(1,cnt,1); for(int i=1;i<=n;i++){ int L = find(x[i]),R=find(y[i]); R--; update(1,cnt,1,L,R,i); } memset(vis,0,sizeof(vis)); int res = 0; for(int i=1;i<cnt;i++){ int v= query(1,cnt,1,i); if(v!=-1&&!vis[v]){ vis[v] = 1; res++; } } cout<<res<<endl; } return 0; }