HDU - 5390 tree 线段树套字典树 (看题解)
Posted cjlhy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU - 5390 tree 线段树套字典树 (看题解)相关的知识,希望对你有一定的参考价值。
看到的第一感觉就是树链剖分 + 线段树套字典树, 感觉复杂度不太对。
其实这种路径其实很特殊, 一个点改变只会影响它儿子到根的路径, 并且这种求最优值问题可以叠加。
所以我们修改的时候对对应dfs序打标记, 询问的时候在线段树上从上往下对每个对应区间求个最优值。
这样还会被卡MLE。。 需要分层优化一下。
#pragma GCC optimize(2) #pragma GCC optimize(3) #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define fio ios::sync_with_stdio(false); cin.tie(0); using namespace std; const int N = 1e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-8; const double PI = acos(-1); template<class T, class S> inline void add(T &a, S b) a += b; if(a >= mod) a -= mod; template<class T, class S> inline void sub(T &a, S b) a -= b; if(a < 0) a += mod; template<class T, class S> inline bool chkmax(T &a, S b) return a < b ? a = b, true : false; template<class T, class S> inline bool chkmin(T &a, S b) return a > b ? a = b, true : false; //mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); const int LOG = 30; int n, m, v[N], tmp[N]; int qus[N][3]; int ans[N]; int Trietot; int ch[N * 40][2], sz[N * 40]; int mx = 0; int newNode() Trietot++; assert(Trietot < N * 40); chkmax(mx, Trietot); ch[Trietot][0] = 0; ch[Trietot][1] = 0; sz[Trietot] = 0; return Trietot; struct Trie int Rt; void init() Rt = newNode(); void ins(int x) int u = Rt; for(int i = LOG - 1; i >= 0; i--) sz[u]++; if(!ch[u][x >> i & 1]) ch[u][x >> i & 1] = newNode(); u = ch[u][x >> i & 1]; sz[u]++; void del(int x) int u = Rt; for(int i = LOG - 1; i >= 0; i--) sz[u]--; u = ch[u][x >> i & 1]; sz[u]--; int query(int x) int u = Rt, ret = 0; if(!sz[u]) return 0; for(int i = LOG - 1; i >= 0; i--) if(sz[ch[u][(x >> i & 1) ^ 1]]) ret += 1 << i; u = ch[u][(x >> i & 1) ^ 1]; else u = ch[u][x >> i & 1]; return ret; T[N << 2]; #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 void build(int tar, int cur, int l, int r, int rt) if(cur == tar) T[rt].init(); return; if(l == r) return; int mid = l + r >> 1; build(tar, cur + 1, lson); build(tar, cur + 1, rson); void update(int tar, int cur, int L, int R, int val, int l, int r, int rt) if(L > R) return; if(L <= l && r <= R) if(cur == tar) if(val > 0) T[rt].ins(val); else T[rt].del(-val); return; if(l == r) return; int mid = l + r >> 1; if(L <= mid) update(tar, cur + 1, L, R, val, lson); if(R > mid) update(tar, cur + 1, L, R, val, rson); int query(int tar, int cur, int p, int val, int l, int r, int rt) if(cur == tar) return T[rt].query(val); if(l == r) return 0; int mid = l + r >> 1; if(p <= mid) return query(tar, cur + 1, p, val, lson); else return query(tar, cur + 1, p, val, rson); void initTrie(int depth) Trietot = 0; build(depth, 0, 1, n, 1); vector<int> G[N]; int in[N], ot[N], idx; void dfs(int u) in[u] = ++idx; for(auto &v : G[u]) dfs(v); ot[u] = idx; void init() idx = 0; for(int i = 1; i <= n; i++) G[i].clear(); int main() int T; scanf("%d", &T); while(T--) scanf("%d%d", &n, &m); init(); for(int i = 2; i <= n; i++) int par; scanf("%d", &par); G[par].push_back(i); for(int i = 1; i <= n; i++) scanf("%d", &v[i]); tmp[i] = v[i]; for(int i = 1; i <= m; i++) scanf("%d%d", &qus[i][0], &qus[i][1]); if(qus[i][0] == 0) scanf("%d", &qus[i][2]); ans[i] = 0; dfs(1); for(int depth = 0; depth <= 17; depth++) initTrie(depth); for(int i = 1; i <= n; i++) v[i] = tmp[i]; update(depth, 0, in[i], ot[i], v[i], 1, n, 1); for(int i = 1; i <= m; i++) if(!qus[i][0]) update(depth, 0, in[qus[i][1]], ot[qus[i][1]], -v[qus[i][1]], 1, n, 1); v[qus[i][1]] = qus[i][2]; update(depth, 0, in[qus[i][1]], ot[qus[i][1]], v[qus[i][1]], 1, n, 1); else chkmax(ans[i], query(depth, 0, in[qus[i][1]], v[qus[i][1]], 1, n, 1)); for(int i = 1; i <= m; i++) if(qus[i][0]) printf("%d\n", ans[i]); return 0; /* */
以上是关于HDU - 5390 tree 线段树套字典树 (看题解)的主要内容,如果未能解决你的问题,请参考以下文章