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 }

先直接贴别人代码。

因为 我们是按照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所有的点,就是该矩形内有多少点的答案了,比较难想。

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

时间: 2024-10-15 14:00:55

TOJ 4105的相关文章

TOJ 4105 Lines Counting(离线树状数组)

4105.   Lines Counting Time Limit: 2.0 Seconds   Memory Limit: 150000K Total Runs: 152   Accepted Runs: 47 On the number axis, there are N lines. The two endpoints L and R of each line are integer. Give you M queries, each query contains two interval

hdu 4105 贪心思想

淋漓尽致的贪心思想 波谷一定是一位数,波峰一位数不够大的时候添加到两位数就一定够大了的. 当在寻找波谷碰到零了就自然当成波谷. 当在寻找波峰时碰到零时,将前面的波谷加到前一个波峰上,让当前的零做波谷,使得波谷的值尽量小,这就是本题最关键的贪心思想,一直想不到. 代码中:a表示前一个值,b表示当前考虑的值,tag为偶数时表示正在寻找波谷,奇数时在寻找波峰. #include<iostream> #include<cstdio> #include<cstring> #inc

bzoj:4105: [Thu Summer Camp 2015]平方运算

Description Input 第一行有三个整数N,M,p,分别代表序列的长度.平方操作与询问操作的总次数以及在平方操作中所要模的数. 接下来一行N个数代表一开始的序列{X1,X2,...,XN}. 接下来M行,每行三个整数op,l,r.其中op代表本次操作的类型.若op=0,代表这是一次平方操作,平方的区间为[l,r]:如果op=1,代表这是一次询问操作,询问的区间为[l,r]. Output 对于每次的询问操作,输出一行代表这段区间内数的总和.注意:答案没有对任何数取模. Sample

TOJ 2850 Corn Fields 状压dp

Source: http://acm.tju.edu.cn/toj/showp.php?pid=2850 题意:n*m的土地上种东西,每个位置分为可以种和不能,种的方案要求不能相邻地种,问合法方案数.(写得有点乱) 分析:做过炮兵阵地,这题就是秒杀了. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 const int mo = 1000000

TOJ 2294 POJ 3286 How many 0&#39;s? 数位dp

http://acm.tju.edu.cn/toj/showp2294.html http://poj.org/problem?id=3284 题外话:集训结束,回学校了.在宿舍看了这题,没什么好想法,去洗澡了.转了两个澡堂都特么没开..倒是在路上把这题想了.用回自己的电脑,不得不说苹果的字体渲染,真心高一个等级. 题意:给定两个数a和b,从a写到b,问一共写了多少个0. 分析:当然先转化为求0..a写多少个0.网上有更简单的做法,就是枚举每位作为0,则如果这一位本来是0,左边取1..a-1(不

TOJ刷题记录(2/50)

P1172:二分,最大化最小值 1 #include <algorithm> 2 #include <bitset> 3 #include <cctype> 4 #include <complex> 5 #include <cstdio> 6 #include <cstring> 7 #include <iostream> 8 #include <map> 9 #include <queue> 10

poj 4105 拯救公主(bfs)

原题网址:http://bailian.openjudge.cn/practice/4105/ 思路: 每个位置包括的状态:所在的位置,获得的宝石. 广搜:用队列存储达到某个位置时,获得的宝石完全相同的最少用时. 传送门另外考虑即可. 详细代码: 1 #include <cstdio> 2 #include <queue> 3 #include <cstring> 4 using namespace std; 5 6 const int INF = 0x44444444

TOJ 1139.Compromise

2015-06-03 问题简述: 大概就是输入两段文本(用小写英文字母表示),分别用#表示一段话的结束输入,输出这两个文本的最长公共子序列. 简单的LCS问题,但是输入的是一段话了,而且公共部分比较是字符串的比较. 原题链接:http://acm.tju.edu.cn/toj/showp.php?pid=1139 解题思路: 简单的最长公共子序列问题,只不过过程中比较的是两个字符串,故使用二维字符数组保存输入文本. 输入 x[1...m][], y[1...n][] ,c[i,j]代表两个文本的

BZOJ 4103~4105 THUSC2015 题解

T1:BZOJ 4013 xor 题目大意:给定一个长度为n的数列a和一个长度为m的数列b,给定矩阵A,令Ai,j=ai⊕bj,q次询问某个子矩形里的k大值 n≤1000,m≤3?105,q≤500 刚看到这题的时候我发现我不会,看到数据范围的时候我发现出题人也不会-- 如果n=1,那么我们对这m个数建立可持久化Trie树,每次询问的时候查询异或a1的k大值即可 那么现在n=1000,我们只需要把这2000棵Trie树放在一起跑即可 时间复杂度O(m?32+n?q?32) 二分答案会T掉. #i