[FJOI2015] division of line tree of Mars store problem

Each inquiry of this question has two intervals, one is time interval and the other is store number interval.
Each purchase is also related to the time store number.
How to connect these two parameters, we need to use the line tree to represent the time interval. The line tree can subdivide the time interval. For each query, it has a time interval [cnt1 − d+1,cnt1][cnt_1-d+1,cnt_1][cnt1 − d+1,cnt1] (t is the current query time, D is the time extended forward in the query) which should be put into the vector on the node of the line tree, and the query number corresponding to [l,r][l,r][l,r] should be saved by the vector on the line tree.
To solve this problem, the purchase is first sorted by store number to complete the second interval variable in the query.
The parameters are now, tl, TR, l, r, which respectively represent the end points of the line tree. The purchase time of tl is in L, r, and the numbers of tl and tr are in order.

#include <bits/stdc++.h>
#define ls (now << 1)
#define rs (now << 1 | 1)
#define mid ((l + r) >> 1)
#define pb(x) push_back(x)
#define LL long long
using namespace std;
inline void read(int &x){
    x = 0; int f = 1; char ch = getchar();
    while (!(ch >= '0' && ch <= '9')){if (ch == '-') f = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
    x *= f;
}
inline void Max(int &x, int y){if (y > x) x = y;}
inline void Min(int &x, int y){if (y < x) x = y;}
const int MAX = 0x7fffffff;
const int MIN = 0x80000000;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 10;
int n, m, cnt1, cnt2, ans[N], rt[N];
struct Add{
    int s, v, t;
    Add(int a = 0, int b = 0, int c = 0){s = a, v = b, t = c;}
} q[N], tmp1[N], tmp2[N];
inline bool cmp(Add &a, Add &b){return a.s < b.s;}
struct Ask{
    int l, r, tl, tr, x;
    Ask(int a = 0, int b = 0, int c = 0, int d = 0, int e = 0){l = a, r = b, tl = c, tr = d, x = e;}
} p[N];
struct Trie{
    struct Node{int son[2], w;} T[N << 5];
    int tot;
    inline void Insert(int &x, int y, int w, int now){
        T[x = ++tot] = T[y]; ++T[x].w;
        if (now == -1) return;
        bool c = w & (1 << now);
        Insert(T[x].son[c], T[y].son[c], w, now - 1);
    }
    inline int query(int x, int y, int w, int now){
        if (now == -1) return 0;
        bool c = w & (1 << now);
        int tmp = T[T[y].son[c ^ 1]].w - T[T[x].son[c ^ 1]].w;
        if (tmp) return query(T[x].son[c ^ 1], T[y].son[c ^ 1], w, now - 1) + (1 << now);
        else return query(T[x].son[c], T[y].son[c], w, now - 1);
    }
}trie;
vector<int> ve[N];
struct Seg{
    inline void Modify(int now, int tl, int tr, int x, int l, int r){
        if (tl > tr) return;
        if (l == tl && r == tr){ve[now].pb(x); return;}
        if (tr <= mid) Modify(ls, tl, tr, x, l, mid);
        else if (tl > mid) Modify(rs, tl, tr, x, mid + 1, r);
        else Modify(ls, tl, mid, x, l, mid), Modify(rs, mid + 1, tr, x, mid + 1, r);
    }
    int top, st[N];
    inline int low(int x){
        int l = 1, r = top;
        while (l <= r){
            if (st[mid] <= x) l = mid + 1;
            else r = mid - 1;
        }
        return r;
    }
    inline void calc(int now, int tl, int tr){
        if (!ve[now].size()) return;
        top = trie.tot = 0;
        for (int i = tl; i <= tr; i++){
            st[++top] = q[i].s;
            trie.Insert(rt[top], rt[top - 1], q[i].v, 17);
        }
        for (int i = 0, sz = ve[now].size(); i < sz; i++){
            int k = ve[now][i];
            int l = low(p[k].l - 1), r = low(p[k].r);
            Max(ans[k], trie.query(rt[l], rt[r], p[k].x, 17));
        }
    }
    //Divide (node number on the line tree, [tl,tr] represents the purchase time on the q array divided by time [l,r])
    //So we divide and conquer every purchase time, and use the vector of the node on the line tree to express the query problem
    //Line tree is only used to save query problems, so that purchase and query have a common time period
    inline void divide(int now, int tl, int tr, int l, int r){
        if (tl > tr) return;
        int t1 = 0, t2 = 0;
        calc(now, tl, tr); if (l == r) return;
        for (int i = tl; i <= tr; i++)
            if (q[i].t <= mid) tmp1[++t1] = q[i];
            else tmp2[++t2] = q[i];
        for (int i = 1; i <= t1; i++) q[i + tl - 1] = tmp1[i];
        for (int i = 1; i <= t2; i++) q[i + tl - 1 + t1] = tmp2[i];
        divide(ls, tl, tl + t1 - 1, l, mid);
        divide(rs, tl + t1, tr, mid + 1, r);
    }
}seg;
int main(){
    read(n), read(m);
    for (int i = 1; i <= n; i++){
        int x; read(x);
        trie.Insert(rt[i], rt[i - 1], x, 17);
    }
    for (int i = 1; i <= m; i++){
        int opt; read(opt);
        if (!opt){
            int s, v; read(s), read(v); ++cnt1;
            q[cnt1] = Add(s, v, cnt1);
        }else{
            int l, r, x, d; read(l), read(r), read(x), read(d);
            ans[++cnt2] = trie.query(rt[l - 1], rt[r], x, 17);
            p[cnt2] = Ask(l, r, max(1, cnt1 - d + 1), cnt1, x);
        }
    }
    for (int i = 1; i <= cnt2; i++)
        seg.Modify(1, p[i].tl, p[i].tr, i, 1, cnt1);
    sort(q + 1, q + 1 + cnt1, cmp);
    seg.divide(1, 1, cnt1, 1, cnt1);
    for (int i = 1; i <= cnt2; i++) printf("%d\n", ans[i]);
    return 0;
}

Posted on Mon, 02 Dec 2019 20:26:34 -0500 by aosmith