BZOJ 3711 [PA2014]Druzyny

来源:互联网 发布:多元数据分析 编辑:程序博客网 时间:2024/09/21 08:18

DP+分治+线段树

似乎有另一种O(nlogn)的做法,就不详细说了。说一种O(nlog2n)的做法。

考虑分治,对于区间[l,r],用[l,mid]来贡献[mid+1,r]
对于一组贡献,设j[l,mid],i[mid+1,r]
j 能贡献给i ,当且仅当,
max{l[k]|j<kmid}ijmin{r[k]|j<kmid}
max{l[k]|mid+1ki}ijmin{r[k]|mid+1ki}
移项一下,
max{l[k]|j<kmid}+jimin{r[k]|j<kmid}+j
imin{r[k]|mid+1ki}jimax{l[k]|mid+1ki}
不等号左右两边分别只和i,j有关,预处理一下。
对于第一个限制可以把j分成两个事件点max{l[k]|j<kmid}+j,min{r[k]|j<kmid}+j,一个加入,一个删除。对于第二个限制用线段树即可。
时间复杂度O(nlog2n),需要一定的常(底)数(层)优化技巧才能通过此题。反正我这样是没过。

#include<cstdio>#include<algorithm>#define N 1000005#define cmax(u,v) (u)<(v)?(u)=(v):0#define cmin(u,v) (u)>(v)?(u)=(v):0#define ainline __inline__ __attribute__((always_inline)) #define MOD 1000000007#define reg registerusing namespace std;namespace runzhe2000{    namespace io    {        const int MaxBuff = 1 << 20;        char B[MaxBuff], *S = B, *T = B;        #define getc() ((S == T) && (T = (S = B) + fread(B, 1, MaxBuff, stdin), S == T) ? 0 : *S++)    }    ainline int read()    {        using namespace io;        #define RG reg        RG char ch; RG int ans = 0; RG bool neg = 0;        while(ch = getc(), (ch < '0' || ch > '9') && ch != '-')     ;        ch == '-' ? neg = 1 : ans = ch - '0';        while(ch = getc(), '0' <= ch && ch <= '9') ans = ans * 10 + ch - '0';        return neg ? -ans : ans;    }    const int INF = 1<<29;    struct event    {        int t, j, type;        bool operator < (const event& that) const        {            if(t == that.t) return type > that.type;            return t < that.t;        }    }ev[1500005];    int n, l[N], r[N], lm[N], rm[N];    struct Pair    {        int f, g;        ainline void fuck(Pair& l, Pair& r)        {            *this=(l.f!=r.f?l.f>r.f?l:r:(Pair){l.f,(l.g+r.g)%MOD});          }        ainline void operator += (const Pair& that)        {            if(f > that.f + 1) return;            if(f <= that.f) *this = (Pair){that.f+1, that.g};            else (g += that.g) %= MOD;        }    }P[N], null;    struct seg    {        Pair p;        int c;    }t[1<<20];    ainline int dmin(reg int a, reg int b){return a<b?a:b;}    ainline int dmax(reg int a, reg int b){return a>b?a:b;}    int ql, qr, qp;    Pair *qpair;    void build(reg int x, reg int l, reg int r)    {        t[x].p = null;        t[x].c = 0;        if(l == r) return;        reg int mid = (l+r)>>1;        build(x<<1,l,mid);        build(x<<1|1,mid+1,r);    }    void query(reg int x, reg int l, reg int r)    {        if(!t[x].c) return;        if(ql <= l && r <= qr) return (void) (*qpair += t[x].p);        reg int mid = (l+r)>>1;         if(ql <= mid) query(x<<1,l,mid);        if(mid < qr ) query(x<<1|1,mid+1,r);    }    void modi(reg int x, reg int l, reg int r)    {        t[x].c += ((qpair->f < 0) ? -1 : 1);        if(l == r){t[x].p = *qpair; return;}        reg int mid = (l+r)>>1;        (qp <= mid)            ? modi(x<<1,l,mid)            : modi(x<<1|1,mid+1,r);        t[x].p.fuck(t[x<<1].p,t[x<<1|1].p);    }    void _solve(reg int L, reg int R, reg int mid)    {        lm[mid] = l[mid+1]; rm[mid] = r[mid+1];        for(int i = mid-1; i >= L; i--) lm[i] = dmax(lm[i+1], l[i+1]), rm[i] = dmin(rm[i+1], r[i+1]);        for(int i = mid+1; i <= R; i++) lm[i] = dmax(lm[i-1], l[i]), rm[i] = dmin(rm[i-1], r[i]);        reg int evcnt = 0;        for(int j = L; j <= mid; j++)        {            if(lm[j] > rm[j] || P[j].f < 0) continue;            ev[++evcnt] = (event){j+lm[j], j,  1};            ev[++evcnt] = (event){j+rm[j], j, -1};        }        sort(ev+1, ev+1+evcnt);        reg int oldcnt=evcnt;        for(int i = mid+1; i <= R; i++) ev[++evcnt] = (event){i,i,0};        std::inplace_merge(ev+1,ev+1+oldcnt,ev+1+evcnt);        build(1,L,mid);        for(int i = 1; i <= evcnt; i++)        {            int j = ev[i].j;             if(ev[i].type == 1) // add                 qp=j,qpair=P+j,modi(1,L,mid);            else if(ev[i].type == -1)  // del                qp=j,qpair=&null,modi(1,L,mid);            else                if((ql=dmax(j-rm[j], L)) <= (qr=dmin(j-lm[j], mid)))                    qpair=P+j,query(1,L,mid);        }    }    void solve(int L, int R)    {        if(L == R) return;        reg int mid = (L+R)>>1;        solve(L,mid);        _solve(L,R,mid);        solve(mid+1,R);    }    void main()    {        n = read();        null = (Pair){-INF,0};        for(int i = 1; i <= n; i++)        {            l[i] = read(), r[i] = read();            P[i] = null;        }        P[0] = (Pair){0,1};        solve(0,n);        if(P[n].f > 0) printf("%d %d\n",P[n].f,P[n].g);        else printf("NIE\n");    }}int main(){    runzhe2000::main();}
0 0
原创粉丝点击