zoukankan      html  css  js  c++  java
  • 求最长的任意两元素差不超过M的子段——双指针+单调队列hdu4123

    换根dp的部分比较容易,难点在于求求最长的任意两元素差不超过M的子段

    首先会想到双指针维护(尺取法),如果p1,p2间的max-min>M,那么p1向右移动,直到p1,p2间的max-min>M

    这个过程可以用线段树(ST)来询问max,min

    另外有一种更强大的方案,因为只要max,min,所以只要维护两个单调队列来解决即可,当max-min>M时取队首元素最远的出队即可

    /*
    第一部分:求出数组a[]
    第二部分:每次询问给出一个Q,求出最长的一段[L,R]使段中任意两个数据的差不超过Q
        用双指针进行维护,用两个单调队列维护这指针间的最大最小值,然后O(n)求每个询问 
    
    */
    #include<bits/stdc++.h>
    #include<queue>
    using namespace std;
    #define N 50006 
    struct Edge{int to,nxt,w;}e[N<<1];
    int head[N],tot,n,m;
    void init(){memset(head,-1,sizeof head);tot=0;}
    void add(int u,int v,int w){
        e[tot].to=v;e[tot].w=w;e[tot].nxt=head[u];head[u]=tot++;
    }
    int d[N],a[N];
    void dfs1(int u,int pre){
        d[u]=0;
        for(int i=head[u];i!=-1;i=e[i].nxt){
            int v=e[i].to;
            if(v==pre)continue;
            dfs1(v,u);
            d[u]=max(d[u],d[v]+e[i].w);
        }
    }
    void dfs2(int u,int pre,int up){
        int mx1=0,mx2=0,id1=0,id2=0;
        for(int i=head[u];i!=-1;i=e[i].nxt){
            int v=e[i].to;
            if(v==pre)continue;
            if(d[v]+e[i].w>=mx1){
                mx2=mx1,id2=id1;
                mx1=d[v]+e[i].w,id1=v;
            }
            else if(d[v]+e[i].w>=mx2)
                mx2=d[v]+e[i].w,id2=v;
        }
        if(up>=mx1){
            mx2=mx1,id2=id1;
            mx1=up,id1=0;
        }
        else if(up>=mx2)
            mx2=up,id2=0;
        a[u]=mx1;    
        
        for(int i=head[u];i!=-1;i=e[i].nxt){
            int v=e[i].to;
            if(v==pre)continue;
            if(v==id1)
                dfs2(v,u,mx2+e[i].w);
            else dfs2(v,u,mx1+e[i].w);
        }
    }
    
    //双指针p,i,两个单调队列维护区间最大值,最小值 
    void solve(int Q){
        deque<int>q1,q2;
        int res=0,p=1;
        for(int i=1;i<=n;i++){
            while(q1.size() && a[q1.back()]>=a[i])q1.pop_back();
            q1.push_back(i); 
            while(q2.size() && a[q2.back()]<=a[i])q2.pop_back();
            q2.push_back(i); 
            
            while(a[q2.front()]-a[q1.front()]>Q){
                p=min(q1.front(),q2.front())+1;
                while(q1.front()<p)q1.pop_front();
                while(q2.front()<p)q2.pop_front();
            }
            res=max(res,i-p+1);
        }
        cout<<res<<endl;
    } 
    
    int main(){
        while(cin>>n>>m && n){
            init();
            for(int i=1;i<n;i++){
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                add(u,v,w);add(v,u,w);
            }
            dfs1(1,1);
            dfs2(1,1,0);
            while(m--){
                int q;scanf("%d",&q);
                solve(q);
            }
        }    
    } 
     
  • 相关阅读:
    fgets()函数读取键盘,去掉换行符或丢弃多余的字符
    c语言gets()函数与它的替代者fgets()函数
    基于京东手机销售数据用回归决策树预测价格
    「我去,这也能行!」令人惊叹的8个深度学习应用
    常见数据结构的 Python 实现(建议收藏)
    60 分钟极速入门 PyTorch
    大牛推荐的15本学习数据分析挖掘的好书
    排名前20的网页爬虫工具
    如何11 周打造全能Python工程师!
    初学者的编程自学指南
  • 原文地址:https://www.cnblogs.com/zsben991126/p/11383616.html
Copyright © 2011-2022 走看看