zoukankan      html  css  js  c++  java
  • 洛谷P5979 [PA2014]Druzyny

    (pre_i) 为只考虑 (d) 的限制下能转移到 (i) 的最小端点,发现 (pre_i) 随着 (i) 单调变化,因此可以通过单调队列求出 (pre_i)

    然后就只用考虑 (c) 的限制了,考虑分治,对于区间 ([l,r]),设 (c_k) 为该区间的最大值,那么先递归 ([l,k-1]),然后处理 ([l,k-1])([k,r]) 的转移,最后递归 ([k,r])

    其中处理转移时,(c) 的限制都一样,进行分类讨论得:

    (pre_i geqslant k) 时,无法转移。

    (l leqslant pre_i < k),在线段树上区间查询即可。

    (pre_i < l and i-c_k < k-1) 时,每次 (i) 变化时,能转移的位置会相应的变化,每次 (O(1)) 维护即可。

    (pre_i<l and i-c_k geqslant k-1) 时,整个左区间都能转移,二分出满足 (pre_j leqslant l) 最大的 (j) 后线段树上区间修改即可。

    得总复杂度为 (T(n)=T(n-x)+T(x)+min(n-x,x)+log n=O(nlog n))

    #include<bits/stdc++.h>
    #define maxn 1000010
    #define maxm 4000010
    #define p 1000000007
    #define ls (cur<<1)
    #define rs (cur<<1|1)
    #define mid ((l+r)>>1)
    #define mk make_pair
    using namespace std;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,root=1,h=1,t,now=1;
    int c[maxn],d[maxn],q[maxn],pre[maxn],pos[maxm];
    pair<int,int> f[maxn],mx[maxm],tag[maxm];
    int mod(int x)
    {
        return x>=p?x-p:x;
    }
    pair<int,int> operator + (const pair<int,int> &a,const pair<int,int> &b)
    {
        if(!b.second) return a;
        if(a.first==b.first) return mk(a.first,mod(a.second+b.second));
        return a.first>b.first?a:b;
    }
    pair<int,int> operator + (const pair<int,int> &a,const int &b)
    {
        return mk(a.first+b,a.second);
    }
    void pushup(int cur)
    {
        pos[cur]=c[pos[ls]]>=c[pos[rs]]?pos[ls]:pos[rs],mx[cur]=mx[ls]+mx[rs];
    }
    void pushtag(int cur,pair<int,int> &v)
    {
        mx[cur]=mx[cur]+v,tag[cur]=tag[cur]+v;
    }
    void pushdown(int cur)
    {
        pushtag(ls,tag[cur]),pushtag(rs,tag[cur]),tag[cur]=mk(0,0);
    }
    void build(int l,int r,int cur)
    {
        if(l==r)
        {
            pos[cur]=l;
            return;
        }
        mx[cur]=tag[cur]=mk(0,0);
        build(l,mid,ls),build(mid+1,r,rs),pushup(cur);
    }
    void update(int L,int R,int l,int r,pair<int,int> &v,int cur)
    {
        if(L<=l&&R>=r)
        {
            pushtag(cur,v);
            return;
        }
        pushdown(cur);
        if(L<=mid) update(L,R,l,mid,v,ls);
        if(R>mid) update(L,R,mid+1,r,v,rs);
        pushup(cur);
    }
    pair<int,int> query(int L,int R,int l,int r,int cur)
    {
        if(L>R) return mk(0,0);
        if(L<=l&&R>=r) return mx[cur];
        pushdown(cur);
        if(R<=mid) return query(L,R,l,mid,ls);
        if(L>mid) return query(L,R,mid+1,r,rs);
        return query(L,R,l,mid,ls)+query(L,R,mid+1,r,rs);
    }
    int ask(int L,int R,int l,int r,int cur)
    {
        if(L<=l&&R>=r) return pos[cur];
        if(R<=mid) return ask(L,R,l,mid,ls);
        if(L>mid) return ask(L,R,mid+1,r,rs);
        int p1=ask(L,R,l,mid,ls),p2=ask(L,R,mid+1,r,rs);
        return c[p1]>=c[p2]?p1:p2;
    }
    int find(int l,int r,int k)
    {
        int pos;
        while(l<=r)
        {
            if(pre[mid]<=k) pos=mid,l=mid+1;
            else r=mid-1;
        }
        return pos;
    }
    void solve(int l,int r)
    {
        if(l==r)
        {
            update(l,l,0,n,f[l],root);
            f[l]=query(l,l,0,n,root);
            return;
        }
        int k=ask(l+1,r,0,n,root);
        solve(l,k-1);
        pair<int,int> val=query(max(pre[k],l),max(k-c[k],l),0,n,root)+1;
        for(int i=max(k,l+c[k]);i<=r;++i)
        {
            if(pre[i]>=k) break;
            if(pre[i]>=l) f[i]=f[i]+(query(pre[i],min(i-c[k],k-1),0,n,root)+1);
            else if(i<k-1+c[k]) f[i]=f[i]+val,val=val+(f[i-c[k]+1]+1);
            else
            {
                int pos=find(i,r,l);
                update(i,pos,0,n,val,root),i=pos;
            }
        }
        solve(k,r);
    }
    int main()
    {
        read(n);
        for(int i=1;i<=n;++i) read(c[i]),read(d[i]);
        for(int i=1;i<=n;++i)
        {
            while(h<=t&&d[i]<=d[q[t]]) t--;
            q[++t]=i;
            while(h<=t&&i-now+1>d[q[h]]) h+=q[h]==now,now++;
            pre[i]=now-1;
        }
        f[0]=mk(0,1),build(0,n,root),solve(0,n);
        if(f[n].first) printf("%d %d",f[n].first,f[n].second);
        else puts("NIE");
        return 0;
    }
    
  • 相关阅读:
    课程作业
    实验5 函数(第4周)
    作业 3 应用分支与循环结构解决问题
    作业 2 分支、循环结构
    作业 1 熟悉C语言编程环境、练习代码录入
    实验 4 在分支循环结构中调用自定义函数
    实验 3 简单的分支与循环结构
    实验 2 用C语言编写简单程序
    实验 1 熟悉C语言编程环境
    课程作业第二章2-6
  • 原文地址:https://www.cnblogs.com/lhm-/p/14243802.html
Copyright © 2011-2022 走看看