zoukankan      html  css  js  c++  java
  • 「ZJOI2018」胖(ST表+二分)

    「ZJOI2018」胖(ST表+二分)

    不开 (O_2) 又没卡过去是种怎么体验。。。

    这可能是 (ZJOI2018) 最简单的一题了。。。我都能 (A)。。。

    首先我们发现这个奇怪的图每个点扩展的是一个区间 ([L,R]),然后我们就可以二分端点了。

    一个点 (x) 扩展到点 (y) 至少要 (|x-y|) 的时间,所以我们把 (a_i) 排个序,在上面二分一个合法的区间使得 (|x-a_l|leq t)(|x-a_r|leq t)

    然后若能扩展到 (y),那么 (0) 号点到 (y) 号点的距离为 (|dis_y-dis_x|+l)。我们用两个 (ST) 表把绝对值拆掉,分别维护最小值即可。

    时间复杂度 (O(nlog^2 n))

    为什么 (dl) 出题人会出到 (2 imes 10^5)。。。两个 (log) 一般只出到 (10^5) 的啊。。。

    (Code Below:)

    // luogu-judger-enable-o2
    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=200000+10;
    int n,m,k,w[maxn],lg[maxn];ll dis[maxn];
    
    struct node{
        int p;ll l;
        node(int p=0,ll l=0):p(p),l(l){}
    }a[maxn];
    inline bool operator < (const node &a,const node &b){
        return a.p<b.p;
    }
    
    struct Sparse_Table{
        ll st[maxn][18];
        inline void init(){
            for(int i=1;i<=k;i++) st[i][0]=a[i].l;
            for(int j=1;j<=lg[k];j++)
                for(int i=1;i+(1<<j)-1<=k;i++) st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
        }
        inline ll query(int l,int r){
            l=max(l,1);r=min(r,n);
            l=lower_bound(a+1,a+k+1,node(l))-a;
            r=upper_bound(a+1,a+k+1,node(r))-a-1;
            if(l>r) return 1e18;
            int k=lg[r-l+1];
            return min(st[l][k],st[r-(1<<k)+1][k]);
        }
    }L,R;
    
    inline int read(){
        register int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return (f==1)?x:-x;
    }
    
    
    inline bool check1(int x,int y){
    //	(2*y-x,y,x]
        if(x==y) return 1;
        ll a=L.query(2*y-x+1,y)+dis[y];
        ll b=R.query(y,x-1)-dis[y];
        ll c=R.query(x,x)-dis[y];
        if(a<=c||b<=c) return 0;
        if(2*y-x>=1) return L.query(2*y-x,2*y-x)+dis[y]>=c;
        return 1;
    }
    
    inline bool check2(int x,int y){
    //	[x,y,2*y-x)
        if(x==y) return 1;
        ll a=L.query(x+1,y)+dis[y];
        ll b=R.query(y,2*y-x-1)-dis[y];
        ll c=L.query(x,x)+dis[y];
        if(a<=c||b<=c) return 0;
        if(2*y-x<=n) return R.query(2*y-x,2*y-x)-dis[y]>c;
        return 1;
    }
    
    inline int solve1(int x){
        int l=1,r=x,mid,ans=0;
        while(l<=r){
            mid=(l+r)>>1;
            if(check1(x,mid)) r=mid-1,ans=mid;
            else l=mid+1;
        }
        return ans;
    }
    
    inline int solve2(int x){
        int l=x,r=n,mid,ans=0;
        while(l<=r){
            mid=(l+r)>>1;
            if(check2(x,mid)) l=mid+1,ans=mid;
            else r=mid-1;
        }
        return ans;
    }
    
    int main()
    {
        n=read(),m=read();
        for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
        for(int i=2;i<=n;i++){
            w[i]=read();
            dis[i]=dis[i-1]+w[i];
        }
        ll ans;
        while(m--){
            k=read();
            for(int i=1;i<=k;i++) a[i].p=read(),a[i].l=read();
            sort(a+1,a+k+1);ans=0;
            for(int i=1;i<=k;i++) a[i].l-=dis[a[i].p];L.init();
            for(int i=1;i<=k;i++) a[i].l+=2*dis[a[i].p];R.init();
            for(int i=1;i<=k;i++) ans+=solve2(a[i].p)-solve1(a[i].p)+1;
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    hdu 5646 DZY Loves Partition
    bzoj 1001 狼抓兔子 平面图最小割
    poj 1815 Friendship 最小割 拆点 输出字典序
    spoj 1693 Coconuts 最小割 二者取其一式
    hdu 5643 King's Game 约瑟夫环变形
    约瑟夫环问题
    hdu 5642 King's Order
    CodeForces 631C Report
    1039: C语言程序设计教程(第三版)课后习题9.4
    1043: C语言程序设计教程(第三版)课后习题10.1
  • 原文地址:https://www.cnblogs.com/owencodeisking/p/10453231.html
Copyright © 2011-2022 走看看