zoukankan      html  css  js  c++  java
  • BZOJ1657 [Usaco2006 Mar]Mooo 奶牛的歌声

    题目大意:n个数,每个数的权值会传给它左右严格大于它的第一个数,求每个数被传到的权值总和。

    题解:

      方法一:如果对于某个数,它左右的最大值都≤它自己,那么它左边就不用传;否则就要传给最接近它的大于它的数。由于需要询问最大值,可用RMQ预处理一波,然后二分地查找:若区间内最大值≤那个“它”,该区间就没有满足要求的数。注意一下左右即可。时间O(nlog(n))。

      方法二:考虑每个数收到的权从哪儿来并到哪儿去。为了简化,先考虑往右传,例如前面有5 3 2三个数,遇到一个4,那么3,2就传给4,并且他们的权与后面的答案毫无关系。根据这个特点建一个单调栈,一旦遇到一个大于栈顶元素的数,就传权并把栈顶元素弹出,接着这个数入栈。左传右传各搞一遍即可。时间O(n)。

    代码

      方法一:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<algorithm>
     5 #include<cctype>
     6 //#include<iostream>
     7 using namespace std;
     8 
     9 int n;
    10 #define maxn 50011
    11 int rmq[maxn][18],H[maxn],V[maxn];
    12 int qread()
    13 {
    14     char c;int s=0;while (!isdigit(c=getchar()));
    15     do {s=s*10+c-'0';} while (isdigit(c=getchar()));
    16     return s;
    17 }
    18 void make_rmq()
    19 {
    20     for (int i=1;i<=n;i++) rmq[i][0]=H[i];
    21     for (int j=1;(1<<j)<=n;j++)
    22         for (int i=1,lar=(1<<j)-1;i+lar<=n;i++)
    23             rmq[i][j]=max(rmq[i][j-1],rmq[i+(1<<(j-1))][j-1]);
    24 }
    25 int voi[maxn];
    26 int ask_rmq(int l,int r)
    27 {
    28     int k=0;
    29     while (l+(1<<k)-1<=r) k++;k--;
    30     return max(rmq[l][k],rmq[r-(1<<k)+1][k]);
    31 }
    32 void play(int l,int r,int d,int x,int y)
    33 {
    34     if (ask_rmq(l,r)<=x) return;
    35     if (d)
    36     {
    37         while (l<r)
    38         {
    39             int mid=(l+r)/2;
    40             if (ask_rmq(l,mid)<=x) l=mid+1;
    41             else r=mid;
    42         }
    43         voi[l]+=y;
    44     }
    45     else
    46     {
    47         while (l<r)
    48         {
    49             int mid=(l+r)/2;
    50             if (ask_rmq(mid+1,r)<=x) r=mid;
    51             else l=mid+1;
    52         }
    53         voi[r]+=y;
    54     }
    55 }
    56 int main()
    57 {
    58     n=qread();
    59     for (int i=1;i<=n;i++) H[i]=qread(),V[i]=qread();
    60     make_rmq();
    61     memset(voi,0,sizeof(voi));
    62     for (int i=1;i<=n;i++)
    63     {
    64         if (i>1) play(1,i-1,0,H[i],V[i]);
    65         if (i<n) play(i+1,n,1,H[i],V[i]);
    66     }
    67     int ans=0;
    68     for (int i=1;i<=n;i++) ans=max(ans,voi[i]);
    69     printf("%d",ans);
    70     return 0;
    71 }
    View Code

      方法二:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<cctype>
     5 //#include<iostream>
     6 using namespace std;
     7 
     8 int qread()
     9 {
    10     char c;int s=0;while (!isdigit(c=getchar()));
    11     do {s=s*10+c-'0';} while (isdigit(c=getchar()));
    12     return s;
    13 }
    14 int n;
    15 #define maxn 50011
    16 int H[maxn],V[maxn],sta[maxn],top=0,voi[maxn];
    17 int main()
    18 {
    19     n=qread();
    20     for (int i=1;i<=n;i++) H[i]=qread(),V[i]=qread();
    21     memset(voi,0,sizeof(voi));
    22     for (int i=1;i<=n;i++)
    23     {
    24         while (top && H[sta[top]]<H[i]) voi[i]+=V[sta[top--]];
    25         sta[++top]=i;
    26     }top=0;
    27     for (int i=n;i>=1;i--)
    28     {
    29         while (top && H[sta[top]]<H[i]) voi[i]+=V[sta[top--]];
    30         sta[++top]=i;
    31     }
    32     int ans=0;
    33     for (int i=1;i<=n;i++) ans=max(voi[i],ans);
    34     printf("%d",ans);
    35     return 0;
    36 }
    View Code
  • 相关阅读:
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
  • 原文地址:https://www.cnblogs.com/Blue233333/p/6164059.html
Copyright © 2011-2022 走看看