zoukankan      html  css  js  c++  java
  • 计蒜客模拟赛5 D2T2 蚂蚁搬家

    很久很久以前,有很多蚂蚁部落共同生活在一片祥和的村庄里。但在某一天,村庄里突然出现了一只食蚁兽,蚂蚁们为了保全性命而决定搬家。

    然而这个村庄四面环山,想要离开这个村庄必须要从地洞里离开,村子里一共有 2n2n2n 个地洞,分布在山的左右,一边 nnn 个。左边的任意一个地洞都可以通到右边 nnn 个地洞中的任意的一个,如图所示(两侧地洞从上至下编号为 111 到 nnn)。

    对于右边的第 iii 个出口,附近有数量为 wiw_iwi​​ 的食物。

    现在前后依次来了 qqq 个蚂蚁部落,第 iii 个部落有 aia_iai​​ 只蚂蚁,它们会从左边第 bib_ibi​​ 个地洞离开,并且选择一个右侧的出口,出口的食物必须大于等于 aia_iai​​,如果有多个满足要求的出口,则选择距离 bib_ibi​​ 最近的(假设蚂蚁从右边的编号为 kkk 的地洞出来,那么距离定义为 ∣k−bi∣|k-b_i|kbi​​∣)。如果有多个洞口符合要求,选择编号最小的出口离开,并且占据这个出口数量为 aia_iai​​ 的食物,当前洞口的食物数量减少 aia_iai​​。

    请输出每群蚂蚁会选择哪个出口,如果没有符合要求的出口,输出 −1-11,并且忽略这群蚂蚁。

    输入格式

    第一行两个整数 nnn 和 qqq。

    接下来 nnn 行,每行一个整数 wiw_iwi​​,表示右方第 iii 个洞口的食物数量。

    接下来 qqq 行,每行两个整数 aia_iai​​ 和 bib_ibi​​,表示蚂蚁数量和它们离开的洞口。

    输出格式

    一共 qqq 行,每行一个整数,表示第 iii 群蚂蚁会选择哪个出口。

    数据规模

    对于 30%30\%30% 的数据:n,q≤3000n,q le 3000n,q3000。

    对于 60%60\%60% 的数据:n,q≤100000n,q le 100000n,q100000。

    对于另外 20%20\%20% 的数据保证:ai=1a_i=1ai​​=1。

    对于 100%100\%100% 的数据:n,q≤500000n,q le 500000n,q500000,ai,wi≤109a_i,w_i le 10^9ai​​,wi​​109​​,bi≤nb_i le nbi​​n。

    更多样例

    样例输入 2

    样例输出 2

    样例解释

    原始的剩余食物为 9,8,6,10,59,8,6,10,59,8,6,10,5。

    查询 4,54,54,5,选择第 555 个洞口出来,剩下食物为 9,8,6,10,19,8,6,10,19,8,6,10,1。

    查询 2,52,52,5,选择第 444 个洞口出来,剩下食物为 9,8,6,8,19,8,6,8,19,8,6,8,1。

    查询 8,18,18,1,选择第 111 个洞口出来,剩下食物为 1,8,6,8,11,8,6,8,11,8,6,8,1。

    查询 9,39,39,3,这时候没有满足条件的洞口了,忽略之。

    查询 3,13,13,1,选择第 222 个洞口出来,剩下食物为 1,5,6,8,11,5,6,8,11,5,6,8,1。

    忽略每行输出的末尾多余空格

    样例输入

    5 5
    9 8 6 10 5
    4 5
    2 5
    8 1
    9 3
    3 1

    样例输出

    5
    4
    1
    -1
    2
    对于30%的数据:n≤300直接暴力找就好

    对于60%的数据:题目要求相当于找距离bi最近的且大于等于ai的位置
    这个可以用二分位置+线段树求区间min实现
    复杂度 O(n lg n)
    如果没有nb的卡常技巧大概是过不了100分的


    对于另外20%的数据:ai =1
    相当于找距离i最近的值≥1的点,我们考虑线段树之外
    的做法
    维护两个并查集,分别指向当前点往上第一个不为0的点和往下第一个不为0的
    点。
    复杂度O(nlgn) 。


    对于 100% 的数据:
    依然考虑用线段树维护,假设现在要找编号小于i的距离i最近的点
    我们记录一个数组pos[i]表示代表位置i的线段树的叶子节点的编号,然后从这个节点往上找
    如果当前点是fa的左儿子,什么也不做,然后向fa走一步
    如果当前点是fa的右儿子,如果fa的左儿子中的最大值≥a[i],那么递归在fa的左儿子中找答案,现
    在区间是一整个节点,就可以利用线段树的二分结构往下找。
    否则什么也不做,然后向fa走一步。
    向右同理
    复杂度O(nlgn)
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 const int inf=2e9;
     8 int n,q,w[500001],c[2000001],L[2000001],R[2000001],pos[500001];
     9 void pushup(int rt)
    10 {
    11     c[rt]=max(c[rt*2],c[rt*2+1]);
    12 }
    13 void build(int rt,int l,int r)
    14 {
    15     L[rt]=l;R[rt]=r;
    16     if (l==r)
    17     {
    18         c[rt]=w[l];
    19         pos[l]=rt;
    20         return;
    21     }
    22     int mid=(l+r)/2;
    23     build(rt*2,l,mid);
    24     build(rt*2+1,mid+1,r);
    25     pushup(rt);
    26 }
    27 void update(int rt,int l,int r,int x,int d)
    28 {
    29     if (l==r)
    30     {
    31         c[rt]+=d;
    32         return;
    33     }
    34     int mid=(l+r)/2;
    35     if (x<=mid) update(rt*2,l,mid,x,d);
    36     else update(rt*2+1,mid+1,r,x,d);
    37     pushup(rt);
    38 }
    39 int take1(int rt,int x)
    40 {
    41     if (L[rt]==R[rt]) return L[rt];
    42     if (c[rt*2+1]>=x) return take1(rt*2+1,x);
    43     return take1(rt*2,x);
    44 }
    45 int take2(int rt,int x)
    46 {
    47     if (L[rt]==R[rt]) return L[rt];
    48     if (c[rt*2]>=x) return take2(rt*2,x);
    49     return take2(rt*2+1,x);
    50 }
    51 int find1(int rt,int x)
    52 {
    53     if (rt==1) return inf;
    54     if (rt&1) 
    55     if (c[rt-1]>=x) return take1(rt-1,x);
    56     return find1(rt/2,x);
    57 }
    58 int find2(int rt,int x)
    59 {
    60     if (rt==1) return inf;
    61     if ((rt&1)==0) 
    62     if (c[rt+1]>=x) return take2(rt+1,x);
    63     return find2(rt/2,x);
    64 }
    65 int main()
    66 {int i,x,y,p1,p2;
    67     cin>>n>>q;
    68     for (i=1;i<=n;i++)
    69     {
    70         scanf("%d",&w[i]);
    71     }
    72     build(1,1,n);
    73     while (q--)
    74     {
    75         scanf("%d%d",&x,&y);
    76         if (w[y]>=x) p1=p2=y;
    77         else p1=find1(pos[y],x),p2=find2(pos[y],x);
    78         if (p1==inf&&p2==inf) printf("-1
    ");
    79         else 
    80         {
    81             if (abs(y-p1)<=abs(p2-y))
    82             {
    83                 printf("%d
    ",p1);
    84                 w[p1]-=x;
    85                 update(1,1,n,p1,-x);
    86             }
    87             else 
    88             {
    89                 printf("%d
    ",p2);
    90                 w[p2]-=x;
    91                 update(1,1,n,p2,-x);
    92             }
    93         }
    94     }
    95 }
  • 相关阅读:
    EFCore.BulkExtensions Demo
    查询处理器用尽了内部资源,无法生成查询计划。这种情况很少出现,只有在查询极其复杂或引用了大量表或分区时才会出现。请简化查询。如果您认为该消息的出现纯属错误,请与客户支持服务部门联系,了解详细信息
    .net core 删除主表,同时删除子表
    java 数据类型优先级
    string.Join 的用法
    JDK-13下载安装及环境变量配置
    Java 前加加和后加加 总结
    变量类型查看-type
    路径:获取 & 更改
    用sql获取数据库中所有的表名、字段名
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7711963.html
Copyright © 2011-2022 走看看