TOJ 4105

题意:有10万个点,10万个询问,没有更新,求L1<=L<=L2,R1<=R<=R2,有多少个,

        其实转换一下:就是求一个矩形 (L1,R1) ----(L2,R2) 中有多少个点(很经典的题)

        这里有比较神奇的做法:基于某种性质。

        解析:

                首先按照 L坐标排序,每个点 也弄成 (R,R,L,0,I)这种形式

                矩形形式是: (L2,R2,L,-1,I) ;和

                                  (L2,R2,R+1,1,I);

            那么,先按照L 排序;

struct Segment{
int x1,x2;
int y,t,id;
Segment(int x1 = 0,int x2 = 0,int y = 0,int t = 0,int id = 0):x1(x1),x2(x2),y(y),t(t),id(id){}
bool operator < (const Segment &a)const{
if(y != a.y) return y < a.y;
return abs(t) > abs(a.t);
}

 

这样;

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N = 100005;
 4 
 5 #define lson l,mid,rt<<1
 6 #define rson mid+1,r,rt<<1|1
 7 #define Mid int mid = (l + r) >> 1
 8 #define root 1,(N - 5),1
 9 
10 struct Segment{
11     int x1,x2;
12     int y,t,id;
13     Segment(int x1 = 0,int x2 = 0,int y = 0,int t = 0,int id = 0):x1(x1),x2(x2),y(y),t(t),id(id){}
14     bool operator < (const Segment &a)const{
15         if(y != a.y) return y < a.y;
16         return abs(t) > abs(a.t);
17     }
18 }ss[N * 3];
19 int sz;
20 struct SegmentTree{
21     int sum[N << 2];
22     void pushup(int rt){
23         sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
24     }
25     void build(int l,int r,int rt){
26         sum[rt] = 0;
27         if(l == r) return;
28         Mid;
29         build(lson);
30         build(rson);
31     }
32     void update(int loc,int l,int r,int rt){
33         if(l == r){
34             sum[rt] ++;
35             return;
36         }
37         Mid;
38         if(loc <= mid) update(loc,lson);
39             else update(loc,rson);
40         pushup(rt);
41     }
42     int query(int L,int R,int l,int r,int rt){
43         if(L <= l && r <= R){
44                 return sum[rt];
45         }
46         Mid;
47         int res = 0;
48         if(L <= mid) res += query(L,R,lson);
49         if(mid + 1 <= R) res += query(L,R,rson);
50         return res;
51     }
52 }sgt;
53 int res[N];
54 int main()
55 {
56     int n,m,l,r;
57     int l2,r2;
58     while(~scanf("%d",&n)){
59         sz = 0;
60         for(int i = 0 ; i < n ; i ++){
61             scanf("%d%d",&l,&r);
62             ss[sz ++] = Segment(r,r,l,0);
63         }
64         scanf("%d",&m);
65         for(int i = 0 ; i < m ; i ++){
66             scanf("%d%d%d%d",&l,&r,&l2,&r2);
67             ss[sz ++] = Segment(l2,r2,l,-1,i);
68             ss[sz ++] = Segment(l2,r2,r + 1,1,i);
69         }
70         
71         for(int i = 0 ; i < m ; i ++) res[i] = 0;
72         sgt.build(root);
73         sort(ss,ss + sz);
74         for(int i = 0 ; i < sz ; i ++){
75             if(ss[i].t == 0) sgt.update(ss[i].x1,root);
76             else if(ss[i].t == -1){
77                 res[ ss[i].id ] -= sgt.query(ss[i].x1,ss[i].x2,root);
78             }
79             else{
80                 res[ ss[i].id ] += sgt.query(ss[i].x1,ss[i].x2,root);
81             }
82         }
83         
84         for(int i = 0 ; i < m ; i ++) printf("%d\n",res[i]);
85     }
86     return 0;
87 }
View Code

先直接贴别人代码。

 因为 我们是按照L 排序的,那么首先更新的事L在前的点。而它只可能对后面的点有影响,并且

是矩形 后面坐标 R1<=R<=R2;的点,因为询问时询问(R1,R2)区间,

只有一种是不符合的,R1<=R<=R2,但是L<L1的点 是不满足的 (想想)

于是我们 只有在去除这些更新的点就好了,所以对于会有:

else if(ss[i].t == -1){
res[ ss[i].id ] -= sgt.query(ss[i].x1,ss[i].x2,root);
}

在l1<=l<=l2的点都更新完了,我们在加上R+1所有的点,就是该矩形内有多少点的答案了,比较难想。

 这道题也因为 区间比较大,所以普通 的二维树状数组 也是不行的

 

posted on 2015-07-12 21:36  forgot93  阅读(198)  评论(0编辑  收藏  举报

导航