題面
注意到邊權只有 \(1,-1\),所以有結論:存在值為 \(v\) 的子段當且僅當 \(v\in[\) 最小子段和,最大子段和 \(]\)。
證明:因為移動區間端點,區間和變化連續(+1/-1),從最小子段移動到最大子段,子段和一定經過 \(v\),所以得證。
於是只要樹剖維護最小最大子段和即可。
和線段樹上維護的資料一樣,查詢時維護兩側的四個資料(Lmax,Rmax,max,sum),轉移時和從線段樹上查詢出的四個資料合併。
注意兩側的轉移是相反的(一個向上一個向下,在加號不同側)。
求最小子段和等於求 原序列全部取負數 的 最大子段和 的 相反數。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node
{
int l, m, r, s;
node operator+(node x)
{
return {max(l, s + x.l), max({m, x.m, r + x.l}), max(x.r, x.s + r), s + x.s};
}
node rev() {swap(l, r); return *this;}
};
const int N = 2e5 + 5;
int b[N], c[N];
vector<int> e[N];
int dfn[N], son[N], sz[N], dep[N], top[N], fa[N], id[N], ts;
struct sgt
{
node a[N << 2];
void pushup(int x)
{
a[x] = a[x << 1] + a[x << 1 | 1];
}
void build(int x, int l, int r, int b[])
{
if(l == r)
{
a[x] = {max(0, b[id[l]]), max(0, b[id[l]]), max(0, b[id[l]]), b[id[l]]};
return;
}
int mid = l + r >> 1;
build(x << 1, l, mid, b);
build(x << 1 | 1, mid + 1, r, b);
pushup(x);
}
node qry(int ql, int qr, int l, int r, int x)
{
if(ql <= l && r <= qr) return a[x];
int mid = l + r >> 1;
if(mid < ql) return qry(ql, qr, mid + 1, r, x << 1 | 1);
if(mid >= qr) return qry(ql, qr, l, mid, x << 1);
return qry(ql, qr, l, mid, x << 1) + qry(ql, qr, mid + 1, r, x << 1 | 1);
}
}t, p;
void dfs1(int x, int fa)
{
son[x] = 0;
::fa[x] = fa;
dep[x] = dep[fa] + 1;
sz[x] = 1;
for(int i : e[x])
{
if(i == fa) continue;
dfs1(i, x);
sz[x] += sz[i];
if(sz[i] > sz[son[x]]) son[x] = i;
}
}
void dfs2(int x, int tp)
{
top[x] = tp;
dfn[x] = ++ts;
id[ts] = x;
if(son[x]) dfs2(son[x], tp);
for(int i : e[x])
if(i != fa[x] && i != son[x])
dfs2(i, i);
}
int n;
int qry(int x, int y, sgt &t)
{
node ans[2] = {{0, 0, 0, 0}, {0, 0, 0, 0}};
int f = 0;
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]]) swap(x, y), f ^= 1;
if(f == 0) ans[f] = ans[f] + t.qry(dfn[top[x]], dfn[x], 1, n, 1).rev();
else ans[f] = t.qry(dfn[top[x]], dfn[x], 1, n, 1) + ans[f];
x = fa[top[x]];
}
if(dep[x] < dep[y]) swap(x, y), f ^= 1;
if(f == 0) ans[f] = ans[f] + t.qry(dfn[y], dfn[x], 1, n, 1).rev();
else ans[f] = t.qry(dfn[y], dfn[x], 1, n, 1) + ans[f];
return (ans[0] + ans[1]).m;
}
struct QU{int x, y, k;}qu[N];
int cntq;
void solve()
{
int q;cin >> q;
n = 1;cntq = 0;ts = 0;
b[1] = 1;c[1] = -1;
e[1].clear();
for(int i = 1; i <= q; i ++)
{
char op;
int x, y, k;
cin >> op >> x >> y;
if(op == '+')
{
n ++;
e[n].clear();
e[x].push_back(n);
e[n].push_back(x);
b[n] = y;
c[n] = -y;
}
else
{
cin >> k;
qu[++cntq] = {x, y, k};
}
}
dfs1(1, 0);
dfs2(1, 1);
t.build(1, 1, n, b);
p.build(1, 1, n, c);
for(int i = 1; i <= cntq; i ++)
{
if(qry(qu[i].x, qu[i].y, t) >= qu[i].k && -qry(qu[i].x, qu[i].y, p) <= qu[i].k) cout << "YES\n";
else cout << "NO\n";
}
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
int t;cin >> t;while(t --) solve();
return 0;
}