zoukankan      html  css  js  c++  java
  • CF526F Pudding Monsters

    Solution

    如果一个 (k*k) 的矩阵里放满了 (k) 个数,容易发现横坐标和纵坐标都是连续的,我们需要利用好这个性质,那么不妨按横坐标排序,之后只有相连的几个点会造成贡献。对于一个区间 ([l,r]),如果它是合法的,当且仅当区间长度等于值域长度(由于合法时值域一定是连续的),即

    [r-l+1=max limits_{lleq ileq r} {y_i}-min limits_{lleq ileq r} {y_i}+1 ]

    对于一个确定的 (r) 只需要统计方程

    [max limits_{lleq ileq r} {y_i}-min limits_{lleq ileq r} {y_i}-r+l=0 ]

    成立的个数。可以用线段树对每一个位置维护这个值。考虑到没有重复的数,值域长度一定大于等于区间长度,那么上式左边会恒大于等于 0,而 (r) 这个单独的位置一定有一个合法解,即会出现 0,所以只需统计区间最小值(0)出现次数就行了。

    对于线段树的维护,考虑增量法。当从 (r) 转移到 (r+1)(r) 会加 1,那么 ([1,r]) 的所有位置的数减 1。对于 (min)(max) 用单调栈维护一下,弹栈时对数列更新一下最大值最小值信息即可。

    考虑到每次弹栈入栈会 (modify) 一次,所以复杂度 (O(nlog n))

    #include<stdio.h>
    #define lid id<<1
    #define rid id<<1|1
    #define N 300007
    
    inline int read(){
        int x=0,flag=1; char c=getchar();
        while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
        return flag? x:-x;
    }
    
    int s[N<<2],num[N<<2],tag[N<<2];
    
    void build(int id,int lf,int rf){
        s[id]=1;
        if(lf==rf) return ;
        int mid=(lf+rf)>>1;
        build(lid,lf,mid);
        build(rid,mid+1,rf);
        s[id]=s[lid]+s[rid];
    }
    
    inline int min(int x,int y){return x<y? x:y;}
    void push(int id,int v){num[id]+=v,tag[id]+=v;}
    void pushdown(int id){push(lid,tag[id]),push(rid,tag[id]),tag[id]=0;}
    void modify(int id,int lf,int rf,int l,int r,int val){
        if(l<=lf&&rf<=r) push(id,val);
        else{
            int mid=(lf+rf)>>1;
            if(tag[id]) pushdown(id);
            if(l<=mid) modify(lid,lf,mid,l,r,val);
            if(r>mid) modify(rid,mid+1,rf,l,r,val);
            num[id]=min(num[lid],num[rid]);
            s[id]=(num[id]==num[lid]? s[lid]:0)+(num[id]==num[rid]? s[rid]:0);
        }
    }
    
    int n,ma[N],mi[N],t1=0,t2=0,a[N];
    int main(){
        n=read();
        for(int i=1;i<=n;i++) a[read()]=read();
        build(1,1,n);
        long long ans=0;
        for(int i=1;i<=n;i++){
            modify(1,1,n,1,i,-1);
            while(t1&&a[ma[t1]]<a[i])
                modify(1,1,n,ma[t1-1]+1,ma[t1],a[i]-a[ma[t1]]),t1--;
            while(t2&&a[mi[t2]]>a[i])
                modify(1,1,n,mi[t2-1]+1,mi[t2],a[mi[t2]]-a[i]),t2--;
            ma[++t1]=mi[++t2]=i;
            ans+=1LL*s[1];
        }
        printf("%lld",ans);
    }
    
  • 相关阅读:
    追求一个人怎么这么难
    基于PHPstream扩展手动实现一个redis客户端
    常见final修饰类
    位运算
    HTTP Status 404
    Hibernate Junit 运行报错:org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment
    根据银行卡号码获取银行卡归属行以及logo图标
    进程间通信IPC(InterProcess Communication)
    脏读、幻读、不可重复读和可重复读
    数据库锁知识总结
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/14157289.html
Copyright © 2011-2022 走看看