hdu-6406 线段树+二分

Posted king-of-dark

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu-6406 线段树+二分相关的知识,希望对你有一定的参考价值。

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

  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 线段树+二分的主要内容,如果未能解决你的问题,请参考以下文章

hdu 6406(思路+数据结构)

HDU 5649 DZY Loves Sorting(二分答案+线段树线段树合并+线段树分割)

线段树分治总结(线段树分治,线段树,并查集,树的dfn序,二分图染色)

二分索引树与线段树分析

大富翁 线段树+二分 +dfs

hdu 4614 线段树 二分