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

 

posted @ 2016-12-12 12:57  Blue233333  阅读(301)  评论(0编辑  收藏  举报