• BZOJ2138 stone


    Link
    考虑一个暴力做法:
    把每个询问拆成(k_i)个点放在左边,每堆石头拆成(a_i)个点放在右边,每个询问的点到在这个询问区间内的石头连一条边,这样我们要做的就是判断有没有完美匹配。
    根据Hall定理,对于任意一个左边的集合,其相邻的右边的点的个数要大于这个集合的大小。
    然后我们发现如果把所有询问按左端点(或者右端点)排个序,那么我们只需要让左边每段区间的点都满足条件就行了。
    并且由于每个询问的点连出来的边都是一样的,所以我们可以把它们合到一起判断。右边的每一堆石头同理。
    那么也就是说,对于任何一段([l,r])区间内的石头,需要满足询问区间完全包含于([l,r])的询问的(k)的和(le sumlimits_{i=l}^r a_i)
    我们记(s)(a)的前缀和数组。
    同时我们注意到不存在区间相互包含,所以设(tl_i)表示左端点在([1,i])区间内的询问的(k)的和,(tr_i)表示右端点在([1,i])区间内的询问的(k)的和。
    那么完全包含于([l,r])的询问的(k)的和就是(tr_r-tl_{l-1})
    我们要满足的条件就变成了(forall lle r,tr_r-tl_{l-1}le s_r-s_{l-1})
    根据下标移项得(s_r-tr_rge s_{l-1}-tl_{l-1})
    得到这个结论之后我们返回来,再按时间来处理询问。
    对于一个询问区间([l,r]),我们需要在选完这个区间的石头之后满足(s_r-tr_rge s_{l-1}-tl_{l-1})成立。
    假如我们在这个区间选了(x)个石头,我们发现只有(tr_r)会增加(x)
    也就是说,(xle (s_r-tr_r)-(s_{l-1}-tl_{l-1}))
    那么当前询问的答案就是(min((s_r-tr_r)-(s_{l-1}-tl_{l-1}),k))
    ((s_r-tr_r)-(s_{l-1}-tl_{l-1}))的最小值就是找到(s_r-tr_r)的最小值和(s_{l-1}-tl_{l-1})的最大值。
    然后更新就是更新(tl,tr)的一段后缀。
    因此我们需要用两个线段树来分别支持查询区间最小值/最大值和区间加。

    #include<bits/stdc++.h>
    #define ls p<<1
    #define rs p<<1|1
    #define mid ((l+r)>>1)
    #define ll long long
    using namespace std;
    const int N=40007,inf=1e9;
    int read(){int x;scanf("%d",&x);return x;}
    int min(int a,int b){return a<b? a:b;}
    int max(int a,int b){return a>b? a:b;}
    ll sqr(int a){return 1ll*a*a;}
    int n,m,a[N],k[N],sum[N],t1[N<<2],t2[N<<2],tag1[N<<2],tag2[N<<2];
    void modify1(int p,int v){t1[p]+=v,tag1[p]+=v;}
    void modify2(int p,int v){t2[p]+=v,tag2[p]+=v;}
    void pushdown1(int p){modify1(ls,tag1[p]),modify1(rs,tag1[p]),tag1[p]=0;}
    void pushdown2(int p){modify2(ls,tag2[p]),modify2(rs,tag2[p]),tag2[p]=0;}
    void pushup1(int p){t1[p]=min(t1[ls],t1[rs]);}
    void pushup2(int p){t2[p]=max(t2[ls],t2[rs]);}
    void build1(int p,int l,int r)
    {
        if(l==r) return (void)(t1[p]=sum[l]);
        build1(ls,l,mid),build1(rs,mid+1,r),pushup1(p);
    }
    void build2(int p,int l,int r)
    {
        if(l==r) return (void)(t2[p]=sum[l]);
        build2(ls,l,mid),build2(rs,mid+1,r),pushup2(p);
    }
    void update1(int p,int l,int r,int L,int R,int x)
    {
        if(L<=l&&r<=R) return (void)(tag1[p]+=x,t1[p]+=x);
        if(tag1[p]) pushdown1(p);
        if(L<=mid) update1(ls,l,mid,L,R,x);
        if(R>mid) update1(rs,mid+1,r,L,R,x);
        pushup1(p);
    }
    void update2(int p,int l,int r,int L,int R,int x)
    {
        if(L<=l&&r<=R) return (void)(tag2[p]+=x,t2[p]+=x);
        if(tag2[p]) pushdown2(p);
        if(L<=mid) update2(ls,l,mid,L,R,x);
        if(R>mid) update2(rs,mid+1,r,L,R,x);
        pushup2(p);
    }
    int query1(int p,int l,int r,int L,int R)
    {
        if(L<=l&&r<=R) return t1[p];
        if(tag1[p]) pushdown1(p);
        return min((L<=mid? query1(ls,l,mid,L,R):inf),(R>mid? query1(rs,mid+1,r,L,R):inf));
     }
    int query2(int p,int l,int r,int L,int R)
    {
        if(R<L) return 0;
        if(L<=l&&r<=R) return t2[p];
        if(tag2[p]) pushdown2(p);
        return max((L<=mid? query2(ls,l,mid,L,R):0),(R>mid? query2(rs,mid+1,r,L,R):0));
    }
    int main()
    {
        n=read();int x,y,z,P;
        x=read(),y=read(),z=read(),P=read();
        for(int i=1;i<=n;++i) sum[i]=sum[i-1]+(a[i]=(sqr(i-x)+sqr(i-y)+sqr(i-z))%P);
        m=read(),k[1]=read(),k[2]=read(),x=read(),y=read(),z=read(),P=read();
        for(int i=3;i<=m;++i) k[i]=(x*k[i-1]+y*k[i-2]+z)%P;
        build1(1,1,n),build2(1,1,n);
        for(int i=1,l,r;i<=m;++i) l=read(),r=read(),printf("%d
    ",k[i]=min(k[i],query1(1,1,n,r,n)-query2(1,1,n,1,l-1))),update1(1,1,n,r,n,-k[i]),update2(1,1,n,l,n,-k[i]);
    }
    
  • 相关阅读:
    Fluxbox 1.0 RC 2
    Cairo 1.2.0
    Transmission 0.6.1
    Xara LX Xtreme 0.5 Rev1175
    Totem 1.4.2
    ImageMagick 6.2.81
    恢复 Firefox 和 Thunderbird 图标
    Conky 1.4.2
    BitTorrent 4.20.0
    Geany 疾速简便的集成启示情况
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11929612.html
Copyright © 2020-2023  润新知