离散化 + 线段树
坐标按从小到大排序,再构造映射。。
View Code
1 //color=0表示未着色或为杂色
2
3 #include <cstdio>
4 #include <cstring>
5 #include <algorithm>
6 using namespace std;
7
8 const int MAXN = 40000 + 5;
9 const int MAX_R = 10000000 + 5;
10
11 int n, ans;
12 bool vis[MAXN] = {};
13 struct SData{ //记录数据
14 int b, e;
15 };
16 SData data[MAXN];
17
18 struct node{ //线段树节点
19 int l, r;
20 int color;
21 };
22 node tree[MAXN * 3];
23
24 struct line{ //s表示端点、num表示该端点是哪个poster的
25 int s, num;
26 };
27 line L[MAXN * 3];
28
29 //建树
30 void build(int i, int ll, int rr){
31 tree[i].l = ll; tree[i].r = rr;
32 tree[i].color = 0; //未着色
33 if(rr != ll){
34 int mid = (ll + rr) / 2;
35 build(2*i, ll, mid);
36 build(2*i+1, mid+1, rr);
37 }
38 }
39
40 //
41 void insert(int i, int ll, int rr, int cc){
42 if(tree[i].l == ll && tree[i].r == rr){
43 tree[i].color = cc;
44 return;
45 }
46 if(tree[i].r == tree[i].l)
47 return;
48
49 if(tree[i].color > 0 && tree[i].color != cc){
50 tree[i<<1].color = tree[i].color;
51 tree[(i<<1)+1].color = tree[i].color;
52 tree[i].color = 0;
53 }
54 int mid = (tree[i].l + tree[i].r) >> 1;
55 if(rr <= mid)
56 insert(i<<1, ll, rr, cc);
57 else if(ll > mid)
58 insert((i<<1) + 1, ll, rr, cc);
59 else{
60 insert(i<<1, ll, mid, cc);
61 insert((i<<1) + 1, mid+1, rr, cc);
62 }
63 }
64
65 void sum ( int i )
66 {
67 if ( tree[i].color )
68 {
69 if ( !vis[tree[i].color] )
70 {
71 vis[tree[i].color]=true;
72 ans++;
73 }
74 return;
75 }
76 sum( i<<1 );
77 sum( (i<<1)+1 );
78 }
79
80 bool cmp(line a, line b){
81 return a.s < b.s;
82 }
83
84 int main(){
85 int c;
86 scanf("%d", &c);
87 while(c--){
88 scanf("%d", &n);
89
90 for(int i=0; i<n; i++){
91 scanf("%d%d", &data[i].b, &data[i].e);
92
93 L[2*i].s = data[i].b; L[2*i].num=-(i+1); //负数表示是poster的左端点
94 L[2*i+1].s = data[i].e; L[2*i+1].num=i+1; //正数表示是右端点
95 }
96
97
98 //离散化……
99 sort(L, L+2*n, cmp);
100 int cnt=1, temp = L[0].s;
101 for(int i=0; i<2*n; i++){
102 if(L[i].s != temp){
103 cnt++;
104 temp=L[i].s;
105 }
106 if(L[i].num < 0) //如果是左端点
107 data[-L[i].num-1].b = cnt;
108 else //如果是右端点
109 data[L[i].num-1].e = cnt;
110 }
111
112
113 //线段树……
114 build(1, 1, cnt);
115
116 for(int i=0; i<n; i++){
117 insert(1, data[i].b, data[i].e, i+1);
118 }
119
120
121 memset(vis, 0, sizeof(vis));
122 ans = 0;
123 sum(1);
124
125 printf("%d\n", ans);
126
127 }
128
129
130 return 0;
131 }
2
3 #include <cstdio>
4 #include <cstring>
5 #include <algorithm>
6 using namespace std;
7
8 const int MAXN = 40000 + 5;
9 const int MAX_R = 10000000 + 5;
10
11 int n, ans;
12 bool vis[MAXN] = {};
13 struct SData{ //记录数据
14 int b, e;
15 };
16 SData data[MAXN];
17
18 struct node{ //线段树节点
19 int l, r;
20 int color;
21 };
22 node tree[MAXN * 3];
23
24 struct line{ //s表示端点、num表示该端点是哪个poster的
25 int s, num;
26 };
27 line L[MAXN * 3];
28
29 //建树
30 void build(int i, int ll, int rr){
31 tree[i].l = ll; tree[i].r = rr;
32 tree[i].color = 0; //未着色
33 if(rr != ll){
34 int mid = (ll + rr) / 2;
35 build(2*i, ll, mid);
36 build(2*i+1, mid+1, rr);
37 }
38 }
39
40 //
41 void insert(int i, int ll, int rr, int cc){
42 if(tree[i].l == ll && tree[i].r == rr){
43 tree[i].color = cc;
44 return;
45 }
46 if(tree[i].r == tree[i].l)
47 return;
48
49 if(tree[i].color > 0 && tree[i].color != cc){
50 tree[i<<1].color = tree[i].color;
51 tree[(i<<1)+1].color = tree[i].color;
52 tree[i].color = 0;
53 }
54 int mid = (tree[i].l + tree[i].r) >> 1;
55 if(rr <= mid)
56 insert(i<<1, ll, rr, cc);
57 else if(ll > mid)
58 insert((i<<1) + 1, ll, rr, cc);
59 else{
60 insert(i<<1, ll, mid, cc);
61 insert((i<<1) + 1, mid+1, rr, cc);
62 }
63 }
64
65 void sum ( int i )
66 {
67 if ( tree[i].color )
68 {
69 if ( !vis[tree[i].color] )
70 {
71 vis[tree[i].color]=true;
72 ans++;
73 }
74 return;
75 }
76 sum( i<<1 );
77 sum( (i<<1)+1 );
78 }
79
80 bool cmp(line a, line b){
81 return a.s < b.s;
82 }
83
84 int main(){
85 int c;
86 scanf("%d", &c);
87 while(c--){
88 scanf("%d", &n);
89
90 for(int i=0; i<n; i++){
91 scanf("%d%d", &data[i].b, &data[i].e);
92
93 L[2*i].s = data[i].b; L[2*i].num=-(i+1); //负数表示是poster的左端点
94 L[2*i+1].s = data[i].e; L[2*i+1].num=i+1; //正数表示是右端点
95 }
96
97
98 //离散化……
99 sort(L, L+2*n, cmp);
100 int cnt=1, temp = L[0].s;
101 for(int i=0; i<2*n; i++){
102 if(L[i].s != temp){
103 cnt++;
104 temp=L[i].s;
105 }
106 if(L[i].num < 0) //如果是左端点
107 data[-L[i].num-1].b = cnt;
108 else //如果是右端点
109 data[L[i].num-1].e = cnt;
110 }
111
112
113 //线段树……
114 build(1, 1, cnt);
115
116 for(int i=0; i<n; i++){
117 insert(1, data[i].b, data[i].e, i+1);
118 }
119
120
121 memset(vis, 0, sizeof(vis));
122 ans = 0;
123 sum(1);
124
125 printf("%d\n", ans);
126
127 }
128
129
130 return 0;
131 }
另附:
【转】
关于这个题离散化的问题,在discuss里有人说测试数据是错的,如果按照一般的离散化的方法去写有种数据不能过
1 10
1 5
8 10
如果像我下面的代码那样写离散化的结果
1 4
1 2
3 4
很明显6-7这条线段在离散化时被消除了
如果想得到正确的结果其实只用在离散化时修改一下就可以了。
如果这两条线段的两个端点是相邻的,cnt++
不相邻cnt+=2;
正确的离散化代码:
View Code
1 for(i=1;i<2*n;i++)
2 {
3 if(L[i].s!=L[i-1].s)
4 {
5 if(L[i-1].s+1==L[i].s)
6 cnt+=1;
7 else
8 cnt+=2;
9 }
10 if(L[i].flag)
11 p[L[i].num].x=cnt;
12 else
13 p[L[i].num].y=cnt;
14 }
2 {
3 if(L[i].s!=L[i-1].s)
4 {
5 if(L[i-1].s+1==L[i].s)
6 cnt+=1;
7 else
8 cnt+=2;
9 }
10 if(L[i].flag)
11 p[L[i].num].x=cnt;
12 else
13 p[L[i].num].y=cnt;
14 }