Codeforces Round #216 (Div. 2) E. Valera and Queries 树状数组 离线处理

题意:n个线段[Li, Ri], m次询问, 每次询问由cnt个点组成,输出包含cnt个点中任意一个点的线段的总数。

由于是无修改的,所以我们首先应该往离线上想, 不过我是没想出来。

首先反着做,先求不包含这个cnt个点的线段的总数, 那么不包含这些点的线段必然在cnt个点之间(这里需要再加两个点一个是0, 一个是MAX),

我们可以把所有线段按R分类, 然后按右端点遍历,对于当前的线段可以在Li 处+1, 然后对于每一次询问中两个点(x, y)之间线段的个数,

只需要查询 左端点大于等于x的个数就好了,这里因为是按右端点从小到大遍历的,所以不用考虑用端点了。

发现, 大多数的离线处理都是先把其中的一维从小到大排序, 然后处理另一维。 这样相当于降维。

 1 #include <bits/stdc++.h>
 2
 3 const int maxn = 1e6 + 10;
 4 typedef std::pair <int, int> pii;
 5 std::vector <int> seg[maxn], q[maxn];
 6 std::vector <pii> rq[maxn];
 7 namespace FenwickTree{
 8     int arr[maxn];
 9     void inc(int x, int d){
10         while (x < maxn){
11             arr[x] += d;
12             x += x & -x;
13         }
14     }
15     int query(int x){
16         int res = 0;
17         while (x > 0){
18             res += arr[x];
19             x -= x & -x;
20         }
21         return res;
22     }
23     int query(int ua, int ub){
24         return query(ub) - query(ua-1);
25     }
26 }
27 int ans[maxn];
28 void init(){
29     memset(ans, 0, sizeof (ans));
30     for (int i = 0; i < maxn; i++){
31         seg[i].clear();
32         q[i].clear();
33         rq[i].clear();
34     }
35 }
36 int main()
37 {
38     #ifndef ONLINE_JUDGE
39         freopen("in.txt", "r", stdin);
40     #endif // ONLINE_JUDGE
41     int n, m;
42     while (~ scanf ("%d%d", &n, &m)){
43         init();
44         for (int i = 0; i < n; i++){
45             int ua, ub;
46             scanf("%d%d", &ua, &ub);
47             ua++, ub++;
48             seg[ub].push_back(ua);
49         }
50         for (int i = 0; i < m; i++){
51             int cnt, p;
52             scanf ("%d", &cnt);
53             q[i].push_back(1);
54             while (cnt--){
55                 scanf ("%d", &p);
56                 p++;
57                 q[i].push_back(p);
58             }
59             q[i].push_back(maxn-1);
60             for (int j = 0; j < q[i].size()-1; j++){
61                 int ua = q[i][j]+1;
62                 int ub = q[i][j+1]-1;
63                 rq[ub].push_back(std::make_pair(ua, i));
64             }
65         }
66         for (int i = 1; i < maxn; i++){
67             for (int j = 0; j < seg[i].size(); j++){
68                 int tmp = seg[i][j];
69                 FenwickTree::inc(seg[i][j], 1);
70             }
71             for (int j = 0; j < rq[i].size(); j++){
72                 int idx = rq[i][j].second;
73                 int tmp = rq[i][j].first;
74                 ans[idx] += FenwickTree::query(rq[i][j].first, i);
75             }
76         }
77         for (int i = 0; i < m; i++){
78             printf("%d\n", n - ans[i]);
79         }
80     }
81     return 0;
82 }
时间: 2024-08-23 15:32:01

Codeforces Round #216 (Div. 2) E. Valera and Queries 树状数组 离线处理的相关文章

Codeforces Round #216 (Div. 2) E. Valera and Queries (BIT)

题目大意: 给出很多条分布在 x 轴上的线段. 然后给出很多点集,问这些点集分布在多少条不同的线段上. 思路分析: 把点集分散成若干条线段. 如果点集做出的线段包含了某一条给出的线段的话,也就是说这个点集上不会有点在这条线段上. 所以我们就是求出 点集做出的线段包含了多少个给出的线段就可以了. 那么也就是比较l r的大小,排序之后用BIT #include <cstdio> #include <iostream> #include <algorithm> #includ

Codeforces Round #470 (Div 2) B 数学 C 二分+树状数组 D 字典树

Codeforces Round #470 B. Primal Sport 数学题,对 x2 和 x1 分解质因子即可. #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b;

Codeforces Round #220 (Div. 2)D. Inna and Sequence 树状数组+二分

题目链接:D. Inna and Sequence 题意:三种操作,1往序列后面加个1,0往序列后面加个0,-1,把给定位置上的数删除. 题解:用树状数组保存的数没被删的个数,每次二分找到位置,然后用数组标记这里被删除. #include<bits/stdc++.h> #include<set> #include<iostream> #include<string> #include<cstring> #include<algorithm&

Codeforces Round #216 (Div. 2)---C. Valera and Elections

The city Valera lives in is going to hold elections to the city Parliament. The city has n districts and n?-?1 bidirectional roads. We know that from any district there is a path along the roads to any other district. Let's enumerate all districts in

Educational Codeforces Round 8(E. Zbazi in Zeydabad(树状数组优化))

题目链接:点击打开链接 题意:一个n*m矩阵, 里面的格子除了'z'就是'.',问有多少个z形图案. 思路:因为n和m很大, 即使n^3复杂度也会超时.  如果按照最朴素的方法, 我们可以处理一下前缀和, 处理出一个格子向左l[i][j].向右r[i][j].斜向左下lr[i][j]连着的z到哪里为止, 这样我们用n^2复杂度枚举每一个格子作为z形图案的右上角,取min(l[i][j], lr[i][j]), 就可以立刻知道这个z形的最左下角到哪里, 然后在这个对角线上扫一遍, 看看向右最远是不

Codeforces 369E Valera and Queries --树状数组+离线操作

题意:给一些线段,然后给m个查询,每次查询都给出一些点,问有多少条线段包含这个点集中的一个或多个点 解法:直接离线以点为基准和以线段为基准都不好处理,“正难则反”,我们试着求有多少线段是不包含某个查询的任意一个点的.这时候我们可以建立点集的补集,以线段的形式,如果点集的补集线段包含了某条给出的线段,那么被包含的那条线段肯定不会包括任意一个点,那么该组查询的答案ans--即可. 用树状数组做,离线读入数据,按容易被包含的线段优先排个序,然后扫一遍,边统计边修改即可. 代码: #include <i

1076E/Educational Codeforces Round 54-E. Vasya and a Tree&lt;&lt;dfs序 树状数组

题意 给定一棵树,初始每个节点权值为零,q次更改,每次修改将以v为顶点的深度为d的子树全部加上x,最后输出所有节点的权重. 思路 题目只要求每个点最后的值,那么经过观察,发现一个点最后的权值大小只与他的父节点的更新有关,那么我们就只需要考虑他的父节点到他这条链上的情况,把这条链拿出来成为线段,然后维护后缀和就能得到此点上的权值.每个节点的贡献为给$[h,h+d]$增加$x$,所以维护时,只要在$h+d$点上加上$x$即可. 但是问题考察的是一棵树,我们就需要动态来完成这条链,我们采用dfs序去扫

Codeforces Round #252 (Div. 2) A - Valera and Antique Items

水题 #include <iostream> #include <set> #include <vector> #include <algorithm> using namespace std; int main(){ int n,v; cin >> n >> v; vector<int> res; for(int i = 0; i < n; ++ i){ int k,s; bool flag = false; ci

递推 Codeforces Round #186 (Div. 2) B. Ilya and Queries

题目传送门 1 /* 2 递推:用cnt记录前缀值,查询区间时,两个区间相减 3 */ 4 #include <cstdio> 5 #include <algorithm> 6 #include <cmath> 7 #include <cstring> 8 using namespace std; 9 10 const int MAXN = 1e5 + 10; 11 const int INF = 0x3f3f3f3f; 12 char s[MAXN]; 1