码迷,mamicode.com
首页 > 其他好文 > 详细

hdu-6406 线段树+二分

时间:2019-10-02 00:20:26      阅读:102      评论:0      收藏:0      [点我收藏+]

标签:产生   状态   个数   typedef   它的   name   必须   前缀   nbsp   

  这个题我觉得题意给你很明显了,就是让你判断这一个改变之后如何让前面和后面接上,熟悉的朋友很容易感觉出这个经典问题,最大值不断变化的值要是在一个数轴上画图像的话,是一个阶梯的形状,所以这个点抬高或降低就有很直观的影响了。

  1.对于这个点被降低:如果这个点不在阶梯的转角上,那么这个点没有任何意义,答案不变,如果在转角上,你要判断这个点下降后前面的最大值现在是多少(设为t),对后续产生了多少的影响,你现在要知道这个点之后的第一个大于t的值在哪即可接的上。

  2.对于这个点被抬高:如果这个点不在阶梯的转角上,还是像后查询第一个大于它的位置就行了,如果这个点不在转角上,但是有突破了阶梯的可能,这个时候前缀的最大值还是变了,查询第一和大于新最大值的位置同理。

  现在还要做的事情有两件:计算从i开始选能选的数量,如何在1p+1~n中查询第一个大于t的位置。

  第一个问题:其实你是可以从后往前维护一个单调栈即可,往里压的时候必须是降序即可。(具体看代码理解比较好一点)

  第二个问题:用线段树维护区间最大值,然后二分就行了。

 

  总结:这道题思路来的很快,先是乱写了两发,根本情况想的非常天真,我太蠢了,乱交。后来预处理后缀居然写了一个线段树+离散的,明明如此复杂,能解决这个问题的方法不止一种,那么我为什么选了一个如此复杂的狗东西呢,下次多想一想不行吗?还有代码出现了bug,不知道是不是状态问题,一个小细节错了,查了好久。最后一个大傻逼bug是我没有计算上什么都没有这种情况的后缀,真是太傻了,思路还是不严谨。

  期望更改方案:正常估计比较难的题多想一想,别脑子一热就写(感觉cf打多,上来一顿胡猜,但是难题别自以为是啊),方法太复杂的时候别觉得自己就是对了,多动脑想一想其他的会死人?还有下次查错,全方位的分析可能发生的所有情况!!!

  

#include<iostream>
#include<cstring>
#include <string>
#include<algorithm>
#include<map>
#include<stack>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long ll;
const int maxn=2e5+20;
int tree[maxn*4];
void insert(int x,int p,int l,int r,int rt)
{
    if(l==x&&r==x)
    {
        tree[rt]=p;
        return;
    }
    int mid=(l+r)/2;
    if(x<=mid)
        insert(x,p, l, mid, lson);
    else
        insert(x,p, mid+1, r, rson);
    tree[rt]=max(tree[lson],tree[rson]);
}
int qu(int L,int R,int l,int r,int rt)
{
   if(L<=l&&r<=R)
   {
       return tree[rt];
   }
   else
   {
       int mid=(l+r)/2;
       int ans=0;
       if(L<=mid)
           ans=max(ans,qu(L, R, l, mid, lson));
       if(R>mid)
           ans=max(ans,qu(L, R, mid+1, r, rson));
       return ans;
   }
}
int ans[maxn],ans_pre[maxn],a[maxn],h[maxn],n,m;
map<int ,int> M;
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        
        for(int i=1;i<=n;i++){
            scanf("%d",&h[i]);
        }
        
        
        
        for(int i=0;i<=4*maxn;i++)
            tree[i]=0;
        
        for(int i=1;i<=n;i++)
            insert(i, h[i], 1, n, 1);
        stack<int> S;
        for(int i=n;i>0;i--)
        {
            while(1){
            if(S.empty()||S.top()>h[i]){
                S.push(h[i]);
                ans[i]=S.size();
                break;
            }
            else
                S.pop();
            }
        }
        
        a[1]=h[1];
        ans_pre[1]=1;
        for(int i=2,j=h[1];i<=n;i++)
        {
            if(h[i]>j)
            {
                ans_pre[i]=ans_pre[i-1]+1;
                j=h[i];
                a[i]=h[i];
            }
            else
            {
                a[i]=a[i-1];
                ans_pre[i]=ans_pre[i-1];
            }
        }
        
        for(int i=0;i<m;i++)
        {
            int p,q;
            scanf("%d%d",&p,&q);
            
            int ans1=ans_pre[p];
            if(a[p]<q)
            {
                if(p!=1&&a[p]==a[p-1])
                    ans1++;
                
                int l=p+1,r=n;
                if(l<=r&&qu(p+1, n, 1, n, 1)>q){
                    while(r>l+1)
                    {
                        int mid=(l+r)/2;
                        if(qu(l, mid, 1, n, 1)>q)
                            r=mid;
                        else
                            l=mid;
                    }
                    if(h[l]<=q)
                        l=r;
                    ans1+=ans[l];
                }
            }
            else if(p==1)
            {
                int l=p+1,r=n;
                if(l<=r&&qu(p+1, n, 1, n, 1)>q){
                    while(r>l+1)
                    {
                        int mid=(l+r)/2;
                        if(qu(l, mid, 1, n, 1)>q)
                            r=mid;
                        else
                            l=mid;
                    }
                    if(h[l]<=q)
                        l=r;
                    ans1+=ans[l];
                }
                
            }
            else if(a[p]!=a[p-1])
            {
                if(q<=a[p-1]){
                    ans1--;
                    q=a[p-1];
                }
                
                int l=p+1,r=n;
                if(l<=r&&qu(p+1, n, 1, n, 1)>q){
                    while(r>l+1)
                    {
                        int mid=(l+r)/2;
                        if(qu(l, mid, 1, n, 1)>q)
                            r=mid;
                        else
                            l=mid;
                    }
                    if(h[l]<=q)
                        l=r;
                    ans1+=ans[l];
                }
            }
            else
                ans1=ans_pre[n];
            printf("%d\n",ans1);
        }
    }
}

 

hdu-6406 线段树+二分

标签:产生   状态   个数   typedef   它的   name   必须   前缀   nbsp   

原文地址:https://www.cnblogs.com/King-of-Dark/p/11616403.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!