zoukankan      html  css  js  c++  java
  • [Swust OJ 746]--点在线上(线段树解法及巧解)

    题目链接:http://acm.swust.edu.cn/problem/746/

    Time limit(ms): 1000      Memory limit(kb): 65535
     

    fate是一个数学大牛,热衷于各种数学问题.一次toshio,lo和fate玩了一个很简单的游戏.


    在一条长40000的数轴上toshio说了M条线段的位置,每条线段给了头和尾的坐标,每条线的坐标都小于等于40000.


    由lo发起N个提问,提问任意说一个点的坐标,要fate说出这个点在多少条线段上.

    Description

    两个整数M和N(0 < N,M <= 40000)


    以下M行,每行两个整数b[i],e[i](0 <= b[i] < e[i] <= 40000)表示第i条线段的两个坐标.(注:点b[i]在线段上,但e[i]不在线段上.)


    接下来N行,每行一个整数,表示lo询问的点的坐标.

    Input

    N行输出


    对于lo询问的N个点,每个点分别在几条线段上.

    Output
    1
    2
    3
    4
    5
    6
    7
    8
    9
    4 3
    1 5
    2 6
    3 7
    4 8
    2
    5
    9
     
    Sample Input
    1
    2
    3
    4
    2
    3
    0
     
    Sample Output
     
     
    这道题可以说是经典的线段树的题目(关于线段树的用法可以看看这里:http://www.cnblogs.com/zyxStar/p/4562917.html
     
    直接上线段树的代码
     
     1 /************************线段树******************************/
     2 
     3 #include <iostream>
     4 #include <cstring>
     5 using namespace std;
     6 const int maxn = 40010;
     7 #define rep(i,a,b) for(int i=a;i<b;i++)
     8 
     9 struct node{
    10     int left, right, mid, val;
    11 }interval[maxn << 2];
    12 
    13 int n, m, x, y;
    14 
    15 //线段树的构建
    16 void build(int left, int right, int k){
    17     interval[k].left = left;
    18     interval[k].right = right;
    19     interval[k].mid = (left + right) / 2;
    20     interval[k].val = 0;
    21     if (left == right)
    22         return;
    23     build(left, interval[k].mid, 2 * k);
    24     build(interval[k].mid + 1, right, 2 * k + 1);
    25 }
    26 
    27 //插入操作寻找[left,right]更新数据
    28 void insert(int left, int right, int k){
    29     if (interval[k].left == left && interval[k].right == right){
    30         interval[k].val++;
    31         return;
    32     }
    33     if (right <= interval[k].mid)
    34         insert(left, right, 2 * k);
    35     else if (left > interval[k].mid)
    36         insert(left, right, 2 * k + 1);
    37     else{
    38         //覆盖重合拆分成两个区间更新数据
    39         insert(left, interval[k].mid, 2 * k);
    40         insert(interval[k].mid + 1, right, 2 * k + 1);
    41     }
    42 }
    43 
    44 //查找算法
    45 int query(int left, int right, int k, int pos){
    46     if (left == right)
    47         return interval[k].val;
    48     if (pos <= interval[k].mid)
    49         return interval[k].val + query(left, interval[k].mid, 2 * k, pos);
    50     else
    51         return interval[k].val + query(interval[k].mid + 1, right, 2 * k + 1, pos);
    52 }
    53 
    54 int main(){
    55     while (cin >> n >> m){
    56         build(0, maxn, 1);
    57         rep(i, 0, n){
    58             cin >> x >> y;
    59             insert(x, --y, 1);
    60         }
    61         rep(i, 0, m){
    62             cin >> x;
    63             cout << query(0, maxn, 1, x) << endl;
    64         }
    65     }
    66     return 0;
    67 }
    View Code

    当然游戏到此还没有结束,发现这道题还有一种巧妙的解法

    像这样只需要开一个数组point,对a,b线段操作的时候,把端点point[a++],point[b++]就可以了,

    到时point[i]+=point[i-1]就可以了,这样就把每个点在几条线上同步了

    比如point[c]+=point[a],从内部区间向外扩散这样就可以表示了,具体的还是看代码理解

     1 #include <stdio.h>
     2 int point[40010];
     3 int main(){
     4     int n, m, i, a, b;
     5     scanf("%d%d", &n, &m);
     6     for (i = 1; i <= n; i++){
     7         scanf("%d%d", &a, &b);
     8         point[a]++;
     9         point[b]--;
    10     }
    11     for (i = 1; i <= 40010; i++)
    12         point[i] += point[i - 1];
    13     for (i = 1; i <= m; i++){
    14         int x;
    15         scanf("%d", &x);
    16         printf("%d
    ", point[x]);
    17     }
    18     return 0;
    19 }
    View Code
  • 相关阅读:
    浅谈Lyndon分解
    【CF914G】Sum the Fibonacci(FWT)
    【洛谷6914】[ICPC2015 WF] Tours(非树边随机边权,树边边权异或)
    【洛谷7143】[THUPC2021 初赛] 线段树(动态规划)
    【洛谷7325】[WC2021] 斐波那契(数论)
    【CF666E】Forensic Examination(广义后缀自动机+线段树合并)
    【CF685C】Optimal Point(二分答案)
    【洛谷7364】有标号二分图计数(多项式开根)
    【CF679E】Bear and Bad Powers of 42(ODT+线段树)
    【洛谷5307】[COCI2019] Mobitel(动态规划)
  • 原文地址:https://www.cnblogs.com/zyxStar/p/4563078.html
Copyright © 2011-2022 走看看