您的位置:首页 > 其它

BZOJ 3711 [PA2014]Druzyny

2017-03-02 07:37 369 查看
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<k≤mid}≤i−j≤min{r[k]|j<k≤mid}

max{l[k]|mid+1≤k≤i}≤i−j≤min{r[k]|mid+1≤k≤i}

移项一下,

max{l[k]|j<k≤mid}+j≤i≤min{r[k]|j<k≤mid}+j

i−min{r[k]|mid+1≤k≤i}≤j≤i−max{l[k]|mid+1≤k≤i}

不等号左右两边分别只和i,j有关,预处理一下。

对于第一个限制可以把j分成两个事件点max{l[k]|j<k≤mid}+j,min{r[k]|j<k≤mid}+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 register
using 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
, r
, lm
, rm
;
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
, 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
.f > 0) printf("%d %d\n",P
.f,P
.g);
else printf("NIE\n");
}
}
int main()
{
runzhe2000::main();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: