LightOj1089(求点包含几个线段 + 线段树)

题目链接

题意:n( n <= 50000 ) 个线段,q ( q <= 50000) 个点,问每个点在几个线段上

线段端点的和询问的点的值都很大,所以必须离散化

第一种解法:先把所有的线段端点和询问点,离散处理,然后对于每条选段处理,c[x]++, c[y + 1]--,然后令c[x] = c[x] + c[x - 1],所以c[x]就保存了被几个线段覆盖,然后对对于每个询问点,查找他在离散后的位置,然后直接读取c[],这种方法很巧妙,佩服佩服

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 using namespace std;
 6 const int Max = 50000 + 10;
 7 int c[4 * Max],a[Max],b[Max],querry[Max];
 8 int id[4 * Max],cnt;
 9 int main()
10 {
11     int n, p, test;
12     scanf("%d", &test);
13     for(int t = 1; t <= test; t++)
14     {
15         printf("Case %d:\n", t);
16         scanf("%d%d", &n, &p);
17         memset(c, 0, sizeof(c));
18         cnt = 0;
19         for(int i = 1; i <= n; i++)
20         {
21             scanf("%d%d", &a[i], &b[i]);
22             id[cnt++] = a[i];
23             id[cnt++] = b[i];
24         }
25         for(int i = 1; i <= p; i++)
26         {
27             scanf("%d", &querry[i]);
28             id[cnt++] = querry[i];
29         }
30         sort(id, id + cnt);
31         cnt = unique(id, id + cnt) - id;
32         for(int i = 1; i <= n; i++)
33         {
34             int x = lower_bound(id, id + cnt, a[i]) - id;
35             int y = lower_bound(id, id + cnt, b[i]) - id;
36             c[x]++;
37             c[y + 1]--;
38         }
39         for(int i = 1; i < 3 * Max; i++)
40             c[i] += c[i - 1];
41
42         for(int i = 1; i <= p; i++)
43         {
44             int x = lower_bound(id, id + cnt, querry[i]) - id;
45             printf("%d\n", c[x]);
46         }
47     }
48     return 0;
49 }

线段树也可解,只是RE

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstdio>
  4 #include <cstring>
  5 using namespace std;
  6 const int Max = 50000 + 10;
  7 struct node
  8 {
  9     int l,r;
 10     int tag,cnt;
 11 };
 12 node tree[4 * Max];
 13 int a[4 * Max], b[4 * Max], c[4 * Max], querry[Max];
 14 int tot;
 15 void buildTree(int left, int right, int k)
 16 {
 17     tree[k].l = left;
 18     tree[k].r = right;
 19     tree[k].tag = -1;
 20     tree[k].cnt = 0;
 21     if(left == right)
 22         return;
 23     int mid = (left + right) / 2;
 24     buildTree(left, mid, k * 2);
 25     buildTree(mid + 1, right, k * 2 + 1);
 26 }
 27 void upDate(int left, int right, int k, int newp)
 28 {
 29     if(tree[k].tag != -1)
 30     {
 31         tree[k * 2].tag = tree[k * 2 + 1].tag = tree[k].tag;
 32         tree[k * 2].cnt++;
 33         tree[k * 2 + 1].cnt++;
 34         tree[k].tag = -1;
 35     }
 36     if(tree[k].l == left && tree[k].r == right)
 37     {
 38         tree[k].cnt++;
 39         tree[k].tag = newp;
 40         return;
 41     }
 42     int mid = (tree[k].l + tree[k].r) / 2;
 43     if(right <= mid)
 44         upDate(left, right, k * 2, newp);
 45     else if(mid < left)
 46         upDate(left, right, k * 2 + 1, newp);
 47     else
 48     {
 49         upDate(left, mid, k * 2, newp);
 50         upDate(mid + 1, right, k * 2 + 1, newp);
 51     }
 52 }
 53 int Search(int k, int value)
 54 {
 55     if(tree[k].l == tree[k].r)
 56         return tree[k].cnt;
 57     if(tree[k].tag != -1)
 58     {
 59         tree[k * 2].tag = tree[k * 2 + 1].tag = tree[k].tag;
 60         tree[k * 2].cnt++;
 61         tree[k * 2 + 1].cnt++;
 62         tree[k].tag = -1;
 63     }
 64
 65     int mid = (tree[k].l + tree[k].r) / 2;
 66     if(value <= mid)
 67         return Search(k * 2, value);
 68     else
 69         return Search(k * 2 + 1, value);
 70 }
 71 int main()
 72 {
 73     int test, n, q;
 74     scanf("%d", &test);
 75     for(int t = 1; t <= test; t++)
 76     {
 77         scanf("%d%d", &n, &q);
 78         tot = 0;
 79         for(int i = 1; i <= n; i++)
 80         {
 81             scanf("%d%d", &a[i], &b[i]);
 82             c[tot++] = a[i];
 83             c[tot++] = b[i];
 84         }
 85         for(int i = 1; i <= q; i++)
 86         {
 87             scanf("%d", &querry[i]);
 88             c[tot++] = querry[i];
 89         }
 90         sort(c, c + tot);
 91         tot = unique(c, c + tot) - c;
 92         buildTree(1, tot, 1);
 93         for(int i = 1; i <= n; i++)
 94         {
 95             int x = lower_bound(c, c + tot, a[i]) - c + 1;
 96             int y = lower_bound(c, c + tot, b[i]) - c + 1;
 97             upDate(x, y, 1, 1);
 98         }
 99         printf("Case %d:\n", t);
100         for(int i = 1; i <= q; i++)
101         {
102             int x = lower_bound(c, c + tot, querry[i]) - c + 1;
103             printf("%d\n", Search(1, x));
104         }
105     }
106     return 0;
107 }

未AC

时间: 2024-10-27 05:23:58

LightOj1089(求点包含几个线段 + 线段树)的相关文章

POJ 2104 求序列里第K大 主席树裸体题

给定一个n的序列,有m个询问 每次询问求l-r 里面第k大的数字是什么 只有询问,没有修改 可以用归并树和划分树(我都没学过..囧) 我是专门冲着弄主席树来的 对主席树的建树方式有点了解了,不过这题为什么是在主席树里面这么操作的 还是有点不懂,今天照着模板敲了一遍就打多校了 再研究吧 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using name

Codevs 1688 求逆序对(权值线段树)

1688 求逆序对 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Description 给定一个序列a1,a2,…,an,如果存在i<j并且ai>aj,那么我们称之为逆序对,求逆序对的数目 数据范围:N<=105.Ai<=105.时间限制为1s. 输入描述 Input Description 第一行为n,表示序列长度,接下来的n行,第i+1行表示序列中的第i个数. 输出描述 Output Description 所

【POJ】1171 求矩形并的周长(线段树+扫描线+离散化)

#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<cmath> using namespace std; #define MAX 10010 #define ls rt<<1 #define rs ls|1 #define m (r+l)>>1

千万别用树套树 【题意:有多少线段完全覆盖某一线段【树状数组维护】】【模板题】

链接:https://ac.nowcoder.com/acm/contest/1108/H Description Bobo 精通数据结构!他想维护一个线段的集合 S.初始时,S 为空.他会依次进行 q 次操作,操作有 2 种. 类型 1:给出 l,?r,向集合 S 中插入线段 [l,?r]. 类型 2:给出 l,?r,询问满足 [x,?y]∈S 且 x?≤?l?≤?r?≤?y 的线段 [x,?y] 数量. 帮 Bobo 求出每次询问的答案. 1?≤?n,?q?≤?105 ti?∈?{1,?2}

HDU3974 Assign the task(多叉树转换为线段+线段树区间染色)

题目大意:有n个人,给你他们的关系(老板和员工),没有直属上司的人就是整个公司的领导者,这意味着n个人形成一棵树(多叉树).当一个人被分配工作时他会让他的下属也做同样的工作(并且立即停止手头正在做的工作),题目会询问你其中某个人正在做的工作. 解题思路:其实从"一个人分配他的下属做一样的工作"这里就可以看出来了,这相当于让一块区间的人都做一样的事,就是线段树区间染色问题.但不能使用线段树,要先将多叉树铺展开,将节点映射到线段上.把每个人的管理区段找出来(把属于同一个人管的放一起,上司放

线段线段

X轴上有N条线段,每条线段包括1个起点和终点.线段的重叠是这样来算的,(10,20)(12,25)的重叠部分为12201220. 给出N条线段的起点和终点,从中选出2条线段,这两条线段的重叠部分是最长的.输出这个最长的距离.如果没有重叠,输出0. Input第1行:线段的数量N(2 <= N <= 50000). 第2 - N + 1行:每行2个数,线段的起点和终点.(0 <= s , e <= 10^9)Output输出最长重复区间的长度.Sample Input 5 1 5 2

String:求str1包含str2的个数

这里用到String类库里的indexOf()函数和subString()函数. 直接贴源码:  static int countStr(String str,String subStr){      int count = 0;   if(str.indexOf(subStr)==-1)    return 0;   else if(str.indexOf(subStr)!=-1){    count++;    count += countStr(str.substring(str.inde

poj2104求区间第k小,静态主席树入门模板

看了很久的主席树,最后看https://blog.csdn.net/williamsun0122/article/details/77871278这篇终于看懂了 #include <stdio.h> #include<algorithm> using namespace std; typedef long long ll; const int maxn = 1e5+5; int T[maxn],L[maxn*20],R[maxn*20],sum[maxn*20]; //sz[]为原

编程之美——3.8求二叉树中结点的最大距离(树,递归,动态规划)

<编程之美>读书笔记12: 3.8 求二叉树中节点的最大距离 问题: 如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的,我们姑且定义"距离"为两节点之间边的个数.写一个程序求一棵二叉树中相距最远的两个节点之间的距离. 实际上就是求树的直径.若采用“动态规划方法”思想,会将该问题分解成“具有最大距离两点间的路径是否经过根节点”两个子问题,然后再对这两个子问题求解判断.实际上,不必这么麻烦.距离最远的两点必然在以某个节点A为根的子树上,它们间的路径必然经过该子树的根节