zoukankan      html  css  js  c++  java
  • [主席树 强制在线]ZOJ3888 Twelves Monkeys

    题意:有n年,其中m年可以乘时光机回到过去,q个询问

    下面m行,x,y 表示可以在y年穿越回x年, 保证y>x

    下面q个询问, 每个询问有个年份k

    问的是k年前面 有多少年可以通过一种以上($ge 2$)方法穿越回去的, 其中时光机只能用一次

    比如案例

    9 3 3
    9 1
    6 1
    4 1
    6
    7
    2

    如图

    对于询问

    6这一年:1.穿越回第1年

          2.等时间过呀过呀过到第9年,再穿越回第1年

    那么第1年就有两种方法可以穿越回去, 同理, 2、3、4年也有同样两种方法(回到1再等时间过呀过 过到2、3、4)

    所以对于6, 有一种以上方法回去的年有1、2、3、4、5总共五年, 输出5

    一开始觉得可以用区间覆盖  覆盖小于两次的就为0, 大于等于2的用rmq找左端点

    后来发现这样并不可行... ... 因为时光机只能用一次, 那么对于类似这种的  5这个点就无法处理啦

    那么换一种想法

    既然要一种以上穿越回去的办法(时间并不会倒流)那么就 要求 该时间点后面至少有两个时间点可以穿越回去 否则答案就为0

    而穿越回去的  离自己最第二远的  就是自己能穿越回的超过一种方法的最远的地方

    来看这个案例

      对于6这个时间,它能穿越回1、2、3、4, 从1可以等到2、3、4

    因此第二小的时间点就是能回去的最远的时间点(超法1种方法)

    那么问题就转化成了如何求区间第二大的问题

    那这不就是主席树的功能了嘛!

    好的,接下来只要把m个穿越的方法当作m个区间处理就好了

    (这里有主席树的小白化解释)

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 typedef pair<int, int> PI;
     5 #define lson l, m
     6 #define rson m+1, r
     7 const int N=50005;
     8 int L[N<<5], R[N<<5], sum[N<<5];
     9 int tot;
    10 int T[N], Hash[N];
    11 int build(int l, int r)
    12 {
    13     int rt=(++tot);
    14     sum[rt]=0;
    15     if(l<r)
    16     {
    17         int m=(l+r)>>1;
    18         L[rt]=build(lson);
    19         R[rt]=build(rson);
    20     }
    21     return rt;
    22 }
    23 
    24 int update(int pre, int l, int r, int x)
    25 {
    26     int rt=(++tot);
    27     L[rt]=L[pre], R[rt]=R[pre], sum[rt]=sum[pre]+1;
    28     if(l<r)
    29     {
    30         int m=(l+r)>>1;
    31         if(x<=m)
    32             L[rt]=update(L[pre], lson, x);
    33         else
    34             R[rt]=update(R[pre], rson, x);
    35     }
    36     return rt;
    37 }
    38 
    39 int query(int u, int v, int l, int r, int k)
    40 {
    41     if(l>=r)
    42         return l;
    43     int m=(l+r)>>1;
    44     int num=sum[L[v]]-sum[L[u]];
    45     if(num>=k)
    46         return query(L[u], L[v], lson, k);
    47     else
    48         return query(R[u], R[v], rson, k-num);
    49 }
    50 
    51 PI a[N];
    52 
    53 int main()
    54 {
    55     int n, m, q;
    56     while(~scanf("%d%d%d", &n, &m, &q))
    57     {
    58         tot=0;
    59         int mm=0;
    60         for(int i=1; i<=m; i++)
    61         {
    62             int x, y;
    63             scanf("%d%d", &x, &y);
    64             if(x>y)
    65                 a[++mm]=make_pair(x, y);
    66         }
    67         m=mm;
    68         sort(a+1, a+1+m);
    69         for(int i=1;i<=m;i++)
    70             Hash[i]=a[i].second;
    71         sort(Hash+1, Hash+1+m);
    72         int d=unique(Hash+1, Hash+1+m)-Hash-1;
    73         T[0]=build(1, d);
    74         for(int i=1; i<=m; i++)
    75         {
    76             int x=lower_bound(Hash+1, Hash+1+d, a[i].second)-Hash;
    77             T[i]=update(T[i-1], 1, d, x);
    78         }
    79         while(q--)
    80         {
    81             int k;
    82             scanf("%d", &k);
    83             int p=lower_bound(a+1, a+1+m, make_pair(k, 0))-a;
    84             if(m-p<1)
    85             {
    86                 puts("0");
    87                 continue;
    88             }
    89             int x=query(T[p-1], T[m], 1, d, 2);
    90             int ans=k-Hash[x];
    91             if(ans<=0)
    92                 puts("0");
    93             else
    94                 printf("%d
    ", ans);
    95         }
    96     }
    97     return 0;
    98 }
    ZOJ 3888
  • 相关阅读:
    10年测试专家深度解读接口测试
    测试技术大牛谈成长经历:一个好的软件测试工程师应该做到这些!
    一位测试老鸟的工作经验分享
    又一名程序员倒下,网友:我们只是新时代农民工
    软件测试工程师这样面试,拿到offer的几率是80%
    App测试流程及测试点(个人整理版)
    自动化测试是什么?
    软件测试工程师的职业技能分析
    月薪15k的测试员需要学习什么技术?
    面向对象
  • 原文地址:https://www.cnblogs.com/Empress/p/4678907.html
Copyright © 2011-2022 走看看