P7707 「Wdsr-2.7」百花齐放的太阳花田 题解
官方题解的卡空间方式是人?
发现
修改只会在尾部加数,非常契合“前缀”这个事情。加数时,对于当前前缀,加的这个数只会影响
那么我们可以对每个前缀开一颗线段树维护每个
回看整个题,尝试将询问区间变为两个前缀相减。但是这样可能会多减一个跨过
总时间复杂度
然后有神秘优化:因为是可持久化线段树,区间加 / 单点查带 tag,空间不如单点加 / 区间查;更新前缀的答案时会存在大量的区间首尾相连,可以合成一个。
::::success[Code]
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
namespace IO {
constexpr int bufsize = 230005;
char buf[bufsize], *f1, *f2;
char gtchar() {return f1 == f2 && (f2 = buf + fread(f1 = buf, 1, bufsize, stdin)) == buf? EOF: *f1++;}
template<typename T> void read(T &ret)
{
int f = ret = 0;
char ch = gtchar();
while(!isdigit(ch)) f = ch == '-', ch = gtchar();
while(isdigit(ch)) ret = (ret << 3) + (ret << 1) + (ch ^ 48), ch = gtchar();
if(f) ret = -ret;
}
template<typename T, typename ...t> void read(T &a, t &...b) {read(a), read(b...);}
}using IO::read;
template<typename t, typename T = t> void chmax(t &a, const T &b) {if(a < b) a = b;}
template<typename t, typename T = t> void chmin(t &a, const T &b) {if(a > b) a = b;}
constexpr int maxn = 5e5 + 5, V = 1e9;
int n, m, K, lstans, h[maxn], t[maxn];
struct seg {
int mn[maxn << 2];
void pushup(int k) {mn[k] = min(mn[k << 1], mn[k << 1 | 1]);}
void modify(int k, int sl, int sr, int q, int val)
{
if(sl == sr) return void(mn[k] = val);
int mid = sl + sr >> 1;
q <= mid? modify(k << 1, sl, mid, q, val)
: modify(k << 1 | 1, mid + 1, sr, q, val);
pushup(k);
}
int queryfir(int k, int sl, int sr, int ql, int qr, int val)// 1st <=val
{
if(mn[k] > val) return -1;
if(sl == sr) return sl;
int mid = sl + sr >> 1;
if(ql <= mid)
{
int t = queryfir(k << 1, sl, mid, ql, qr, val);
if(~t) return t;
}
if(qr > mid) return queryfir(k << 1 | 1, mid + 1, sr, ql, qr, val);
return -1;
}
int querylst(int k, int sl, int sr, int ql, int qr, int val)// 1st <=val
{
if(mn[k] > val) return -1;
if(sl == sr) return sl;
int mid = sl + sr >> 1;
if(qr > mid)
{
int t = querylst(k << 1 | 1, mid + 1, sr, ql, qr, val);
if(~t) return t;
}
if(ql <= mid) return querylst(k << 1, sl, mid, ql, qr, val);
return -1;
}
}Th;
struct preseg {
struct node {
int l, r, v;
}s[maxn * 50];//!
int cnt;
#define l(k) s[k].l
#define r(k) s[k].r
#define v(k) s[k].v
void modify(int &nk, int k, int sl, int sr, int q, int delta)
{
if(nk == k) s[nk = ++cnt] = s[k];
v(nk) += delta;
if(sl == sr) return;
int mid = sl + sr >> 1;
q <= mid? modify(l(nk), l(k), sl, mid, q, delta)
: modify(r(nk), r(k), mid + 1, sr, q, delta);
}
int query(int k, int sl, int sr, int ql, int qr)
{
if(!k || ql <= sl && sr <= qr) return v(k);
int mid = sl + sr >> 1, ret = 0;
if(ql <= mid) ret = query(l(k), sl, mid, ql, qr);
if(qr > mid) ret += query(r(k), mid + 1, sr, ql, qr);
return ret;
}
#undef l
#undef r
#undef v
}Tans;
int rt[maxn];
struct Chtholly {
struct node {
int l, r, v;
friend bool operator < (node a, node b) {return a.l < b.l;}
};
int lim;
set<node> S;
void init(int LIM) {S.insert({1, lim = LIM, -1});}
auto split(int x)//[x,...)
{
if(x > lim) return S.end();
auto it = prev(S.upper_bound({x, lim + 1, -1}));
if(it->l == x) return it;
int l = it->l, r = it->r, v = it->v;
S.erase(it); S.insert({l, x - 1, v});
return S.insert({x, r, v}).first;
}
void append(int k, int val, int kind)
{
rt[k] = rt[k - 1];
auto itl = split(val);
vector<int> vec;
for(auto it = itl; it != S.end(); ++it) if(it->v != kind)
{
if(vec.size() && vec.back() == it->l) vec.pop_back();
else vec.push_back(it->l);
vec.push_back(it->r + 1);
}
for(int i = 0, j = 1; i < vec.size(); i++, j = -j)
if(vec[i] <= V) Tans.modify(rt[k], rt[k - 1], 1, V, vec[i], j);
S.erase(itl, S.end());
S.insert({val, lim, kind});
}
}Tlst;
void append(int nh, int nt)
{
++n, h[n] = nh, t[n] = nt;
Tlst.append(n, nh, nt);
Th.modify(1, 1, maxn - 5, n, nh);
}
int query(int r, int x) {return Tans.query(rt[r], 1, V, 1, x);}
int query(int l, int r, int x)
{
// printf("r:%d\n", query(r, x));
if(l == 1) return query(r, x);
int ans = query(r, x) - query(l - 1, x);
int lst = Th.querylst(1, 1, maxn - 5, 1, l - 1, x), fir = Th.queryfir(1, 1, maxn - 5, l, r, x);
if(lst != -1 && fir != -1 && t[lst] == t[fir]) ++ans;
return ans;
}
int main()
{
Tlst.init(V);
read(n, m, K);
for(int i = 1; i <= n; i++) read(h[i]);
for(int i = 1; i <= n; i++) read(t[i]);
int nn = n; n = 0;
for(int i = 1; i <= nn; i++) append(h[i], t[i]);
assert(nn == n);
for(int i = 1, op, l, r, x; i <= m; i++)
{
read(op, l, r);
l ^= K * lstans, r ^= K * lstans;
if(op == 1)// qry
{
read(x), x ^= K * lstans;
printf("%d\n", lstans = query(l, r, x));
}
else append(l, r);
}
return 0;
}
::::