zoukankan      html  css  js  c++  java
  • 2018宁夏邀请赛 Continuous Intervals(单调栈 线段树

    https://vjudge.net/problem/Gym-102222L

    题意:给你n个数的序列,让判断有几个区间满足排完序后相邻两数差都不大于1。

    题解:对于一个区间 [L,R],记最大值为 max、最小值为 min、数 字种类数为 cnt,那么这个区间是 continuous interval 当且 仅当 max−min+ 1 = cnt。 考虑从小到大枚举 R,用线段树维护每个 L 的区间 [L,R] 的 max−min−cnt 的值。 由于总有 max−min+1 ≥cnt,那么只需要维护线段树上每 个 L 对应的 max−min−cnt 的最小值,以及有多少个 L 取 到这个最小值。 当 R 变大时,每个 L 对应的三个值都需要进行修改。对于 max 和 min,可以用单调栈来维护后缀 max 和 min,然后在 线段树上进行区间加减操作,对于 cnt,只需要在线段树上 对区间 [lastai + 1,R] 进行加减操作。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2000010;
    int Mn[maxn],lazy[maxn],sum[maxn],a[maxn];
    int q1[maxn],t1,q2[maxn],t2;
    map<int,int>mp;
    void build(int Now,int L,int R)
    {
        sum[Now]=R-L+1; Mn[Now]=lazy[Now]=0;
        if(L==R) return ; int Mid=(L+R)>>1;
        build(Now<<1,L,Mid);
        build(Now<<1|1,Mid+1,R);
    }
    void pushdown(int Now)
    {
        if(!lazy[Now]) return ;
        Mn[Now<<1]+=lazy[Now]; Mn[Now<<1|1]+=lazy[Now];
        lazy[Now<<1]+=lazy[Now]; lazy[Now<<1|1]+=lazy[Now];
        lazy[Now]=0;
    }
    void pushup(int Now)
    {
        Mn[Now]=min(Mn[Now<<1],Mn[Now<<1|1]);
        if(Mn[Now<<1]==Mn[Now<<1|1]) sum[Now]=sum[Now<<1]+sum[Now<<1|1];
        else if(Mn[Now<<1]<Mn[Now<<1|1]) sum[Now]=sum[Now<<1];
        else sum[Now]=sum[Now<<1|1];
    }
    void update(int Now,int L,int R,int l,int r,int v)
    {
        if(l>r) return ;
        if(L==R) {
            Mn[Now]+=v;
            return ;
        }
        if(l<=L&&r>=R){
            Mn[Now]+=v; lazy[Now]+=v;
            return ;
        }
        int Mid=(L+R)>>1; pushdown(Now);
        if(l<=Mid) update(Now<<1,L,Mid,l,r,v);
        if(r>Mid) update(Now<<1|1,Mid+1,R,l,r,v);
        pushup(Now);
    }
    int main()
    {
        int T,N,C=0; ll ans;
        scanf("%d",&T);
        while(T--){
            scanf("%d",&N);
            rep(i,1,N) scanf("%d",&a[i]);
            build(1,1,N);
            t1=t2=0; ans=0;  mp.clear();
            rep(i,1,N){
                update(1,1,N,i,i,-1);
                while(t1&&a[i]>=a[q1[t1]]){
                    update(1,1,N,q1[t1-1]+1,q1[t1],a[i]-a[q1[t1]]);
                    t1--;
                }
                q1[++t1]=i; //单减栈
    
                while(t2&&a[i]<=a[q2[t2]]){
                    update(1,1,N,q2[t2-1]+1,q2[t2],a[q2[t2]]-a[i]);
                    t2--;
                }
                q2[++t2]=i; //单增栈
    
                update(1,1,N,mp[a[i]]+1,i-1,-1); mp[a[i]]=i;
                ans+=sum[1];
            }
            printf("Case #%d: %lld
    ",++C,ans);
        }
        return 0;
    }
    
  • 相关阅读:
    JavaCC 研究与应用( 8000字 心得 源程序)
    推荐UML插件Green UML、AmaterasUML
    Custom PMD Rules
    静态分析工具及使用总结(三)
    静态分析工具及使用总结(二)CheckStyle
    静态分析工具及使用总结(一)
    基于antlr的表达式解析器——函数类型验证
    基于antlr的表达式解析器——函数生成(通过freemarker)
    网络流--最大流--hlpp(预流推进)模板
    网络流--最大流--Dinic模板矩阵版(当前弧优化+非当前弧优化)
  • 原文地址:https://www.cnblogs.com/wzgg/p/11461533.html
Copyright © 2011-2022 走看看