[Codeforces167D]Wizards and Roads 笛卡尔树分裂合并

每次将平面上y坐标最大的点拿出来,将坐标系按照这个点分成两半,连接左右半坐标系里面y坐标最大的点,构成一棵笛卡尔树,由于数据随机所以深度是logn的

题目相当于求一个区间内的最大匹配个数,这可以在笛卡尔树上维护
询问每次需要分裂出来一个笛卡尔树,按照非旋转Treap那样子分裂合并就行了

#include <bits/stdc++.h>

#define p 1000000009
#define N 200050

#define O tr[t]
#define L tr[ tr[t].l ]
#define R tr[ tr[t].r ]

#define x first
#define y second
#define MP make_pair

using namespace std;
typedef pair<int,int> pii;
inline int rd() { int r; scanf("%d",&r); return r; }

pii A[N];
int cnt,n,m,rt,a,b,c,d,k;
void GP(int &a,int &b,pii P) { a = P.x, b = P.y; }
struct Node{ int l,r,siz,key,F,G; }tr[N];
int up(int t) {
    O.siz = L.siz + R.siz + 1;
    if (!O.l && !O.r) { O.F = O.G = 0; return t; }
    if (!O.l) {
        O.F = R.G;
        O.G = R.F + 1;
        return t;
    }
    if (!O.r) {
        O.F = L.G;
        O.G = L.F + 1;
        return t;
    }
    O.F = L.G + R.G;
    O.G = max( L.F+R.G, L.G+R.F ) + 1;
    return t;
}

void build(int l,int r,int &t) {
    if (l > r) return ;
    int now = -1, lo = 0;
    for (int _=l;_<=r;_++)
        A[_].y > now ? now = A[_].y, lo = _ : 0;
    tr[ t=++cnt ].key = A[lo].y;
    build(l,lo-1,O.l);
    build(lo+1,r,O.r);
    up(t);
}

pii spl(int t,int k) {
    int tmp;
    if (!k) return MP(0,t);
    if (k == O.siz) return MP(t,0);
    return L.siz + 1 <= k ? 
        ( GP(O.r, tmp, spl(O.r,k-L.siz-1)), up(t), MP(t,tmp) ):
        ( GP(tmp, O.l, spl(O.l,k))        , up(t), MP(tmp,t) );
}

int mer(int x,int y) {
    if (!x || !y) return x+y;
    return tr[x].key > tr[y].key ?
        ( tr[x].r = mer(tr[x].r, y), up(x) ):
        ( tr[y].l = mer(x, tr[y].l), up(y) );
}

void solve() {
    for (int _=k+1;_<=n;_++) 
        A[_].x =(1LL*a*A[_-1].x+b) %p, A[_].y = (1LL*c*A[_-1].y+d) %p;
    sort(A+1,A+n+1);
    build(1,n,rt);
    m = rd();
    while (m--) {
        int ll = rd(), rr = rd(),r1,r2; pii tmp;

        tmp.x = ll, tmp.y = 0;
        ll = (int)(lower_bound(A+1,A+n+1,tmp) - A) - 1;
        GP(r1,rt,spl(rt,ll));

        tmp.x = rr+1, tmp.y = 0;
        rr = (int)(lower_bound(A+1,A+n+1,tmp) - A - 1) - ll;
        GP(rt,r2,spl(rt,rr));

        printf("%d\n",max(tr[rt].F, tr[rt].G));

        rt = mer(r1,rt);
        rt = mer(rt,r2);
    }
}

void init() {
    n = rd(), k = rd();
    for (int _=1;_<=k;_++) A[_].x = rd(), A[_].y = rd();
    a = rd(), b = rd(), c = rd(), d =rd();
}

int main() {
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
    #endif
    init();
    solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值