2017.10.6 BJOI2015 bzoj4336 骑士的旅行
2017-10-17 20:11
232 查看
骑士的旅行
题目背景:
bzoj4336
分析:树链剖分 + 树状数组 + 权值线段树 + 二分
本场考试唯一一道我看了就知道怎么做的题······直接大数据结构暴力······
首先很显然的,需要
提取链上的信息 è 树链剖分
维护权值相关并且支持区间查询 è 主席树
维护单点修改 è 主席树换成树状数组 + 权值线段树
然后之后就是暴力的打代码就好了······按理说的最坏复杂度应该是O(nklog3n),不过因为树链剖分的常数很小,树状数组常数也小,线段树也不是全部都能跑满,再加上数据不是卡的太死,修改操作的O(log2n)复杂度也很稳,所以貌似跑的还比较快。
算法实现:
1、先树链剖分,方便过后提取链询问
2、然后将每一个骑士所在结点编号插入到对应的链剖过后的新编号上
3、针对每一次询问,提取出对应的区间所在的(log2n)个结点,然后进行k次二分,找到相应的k大值
4、针对每一次修稿,暴力在树状数组上修改logn次即可
Source:
题目背景:
bzoj4336
分析:树链剖分 + 树状数组 + 权值线段树 + 二分
本场考试唯一一道我看了就知道怎么做的题······直接大数据结构暴力······
首先很显然的,需要
提取链上的信息 è 树链剖分
维护权值相关并且支持区间查询 è 主席树
维护单点修改 è 主席树换成树状数组 + 权值线段树
然后之后就是暴力的打代码就好了······按理说的最坏复杂度应该是O(nklog3n),不过因为树链剖分的常数很小,树状数组常数也小,线段树也不是全部都能跑满,再加上数据不是卡的太死,修改操作的O(log2n)复杂度也很稳,所以貌似跑的还比较快。
算法实现:
1、先树链剖分,方便过后提取链询问
2、然后将每一个骑士所在结点编号插入到对应的链剖过后的新编号上
3、针对每一次询问,提取出对应的区间所在的(log2n)个结点,然后进行k次二分,找到相应的k大值
4、针对每一次修稿,暴力在树状数组上修改logn次即可
Source:
/* created by scarlyw */ #include <cstdio> #include <string> #include <algorithm> #include <cstring> #include <iostream> #include <cmath> #include <cctype> #include <vector> #include <set> #include <queue> #include <ctime> inline char read() { static const int IN_LEN = 1024 * 1024; static char buf[IN_LEN], *s, *t; if (s == t) { t = (s = buf) + fread(buf, 1, IN_LEN, stdin); if (s == t) return -1; } return *s++; } ///* template<class T> inline void R(T &x) { static char c; static bool iosig; for (c = read(), iosig = false; !isdigit(c); c = read()) { if (c == -1) return ; if (c == '-') iosig = true; } for (x = 0; isdigit(c); c = read()) x = ((x << 2) + x << 1) + (c ^ '0'); if (iosig) x = -x; } //*/ const int OUT_LEN = 1024 * 1024; char obuf[OUT_LEN], *oh = obuf; inline void write_char(char c) { if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf; *oh++ = c; } template<class T> inline void W(T x) { static int buf[30], cnt; if (x == 0) write_char('0'); else { if (x < 0) write_char('-'), x = -x; for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48; while (cnt) write_char(buf[cnt--]); } } inline void flush() { fwrite(obuf, 1, oh - obuf, stdout); } /* template<class T> inline void R(T &x) { static char c; static bool iosig; for (c = getchar(), iosig = false; !isdigit(c); c = getchar()) if (c == '-') iosig = true; for (x = 0; isdigit(c); c = getchar()) x = ((x << 2) + x << 1) + (c ^ '0'); if (iosig) x = -x; } //*/ const int MAXN = 40000 + 10; const int MAXX = 1000 + 3; int n, m, q, x, y, k, cnt, ind, type; int size[MAXN], father[MAXN], top[MAXN], son[MAXN], num[MAXN], dep[MAXN]; int f[MAXN], p[MAXN]; int root[MAXN]; std::vector<int> edge[MAXN]; struct node { int cnt, left, right; } tree[MAXN * 300]; inline void add_edge(int x, int y) { edge[x].push_back(y), edge[y].push_back(x); } inline void dfs1(int cur, int fa) { size[cur] = 1, father[cur] = fa, dep[cur] = dep[fa] + 1; for (int p = 0; p < edge[cur].size(); ++p) { int v = edge[cur][p]; if (v != fa) { dfs1(v, cur), size[cur] += size[v]; if (size[v] > size[son[cur]]) son[cur] = v; } } } inline void dfs2(int cur, int tp) { top[cur] = tp, num[cur] = ++ind; if (son[cur]) dfs2(son[cur], tp); for (int p = 0; p < edge[cur].size(); ++p) { int v = edge[cur][p]; if (num[v] == 0) dfs2(v, v); } } inline void solve_tree() { R(n); for (int i = 1; i < n; ++i) R(x), R(y), add_edge(x, y); dfs1(1, 0), dfs2(1, 1); } inline int lowbit(int i) { return i & -i; } inline void insert(int &cur, int l, int r, int x, int k) { if (cur == 0) cur = ++cnt; tree[cur].cnt += k; if (l == r) return ; int mid = l + r >> 1; if (x <= mid) insert(tree[cur].left, l, mid, x, k); else insert(tree[cur].right, mid + 1, r, x, k); } inline void insert(int i, int x, int k) { for (; i <= n; i += lowbit(i)) insert(root[i], 1, MAXX, x, k); } inline void query(int i, int *a, int &cnt_a) { for (; i; i -= lowbit(i)) a[++cnt_a] = root[i]; } inline void solve_knight_pos() { R(m); for (int i = 1; i <= m; ++i) R(f[i]), R(p[i]), insert(num[p[i]], f[i], 1); } inline void solve(int u, int v) { static int a[MAXN], b[MAXN], c[MAXN], d[MAXN]; static int cnt_a, cnt_b; cnt_a = cnt_b = 0; int p = u, q = v; while (top[p] != top[q]) { dep[top[p]] > dep[top[q]] ? (query(num[p], b, cnt_b), query(num[top[p]] - 1, a, cnt_a), p = father[top[p]]) : (query(num[q], b, cnt_b), query(num[top[q]] - 1, a, cnt_a), q = father[top[q]]); } dep[p] > dep[q] ? (query(num[p], b, cnt_b), query(num[q] - 1, a, cnt_a)) : (query(num[q], b, cnt_b), query(num[p] - 1, a, cnt_a)) ; int sum = 0, q_sum = 0; for (int j = 1; j <= cnt_a; ++j) q_sum -= tree[a[j]].cnt; for (int j = 1; j <= cnt_b; ++j) q_sum += tree[b[j]].cnt; sum = q_sum, sum = std::min(sum, k); if (sum == 0) W(-1); for (int i = 0; i < sum; ++i) { for (int j = 1; j <= cnt_a; ++j) c[j] = a[j]; for (int j = 1; j <= cnt_b; ++j) d[j] = b[j]; int l = 1, r = MAXX, k = q_sum - i; while (l != r) { int left_sum = 0, mid = l + r >> 1; for (int j = 1; j <= cnt_b; ++j) left_sum += tree[tree[d[j]].left].cnt; for (int j = 1; j <= cnt_a; ++j) left_sum -= tree[tree[c[j]].left].cnt; if (left_sum >= k) { for (int j = 1; j <= cnt_a; ++j) c[j] = tree[c[j]].left; for (int j = 1; j <= cnt_b; ++j) d[j] = tree[d[j]].left; r = mid; } else { for (int j = 1; j <= cnt_a; ++j) c[j] = tree[c[j]].right; for (int j = 1; j <= cnt_b; ++j) d[j] = tree[d[j]].right; l = mid + 1, k -= left_sum; } } W(l), write_char(' '); } write_char('\n'); } inline void solve_query() { R(q), R(k); while (q--) { R(type), R(x), R(y); switch (type) { case 1: solve(x, y); break ; case 2: insert(num[p[x]], f[x], -1), p[x] = y; insert(num[p[x]], f[x], 1); break ; case 3: insert(num[p[x]], f[x], -1), f[x] = y; insert(num[p[x]], f[x], 1); break ; } } } int main() { solve_tree(); solve_knight_pos(); solve_query(); flush(); return 0; }
相关文章推荐
- [BZOJ]4336: BJOI2015 骑士的旅行 树链剖分+STL(multiset)
- [BZOJ4336][BJOI2015]骑士的旅行(树链剖分+线段树+multiset+归并)
- BZOJ 4336 BJOI2015 骑士的旅行
- 4336: BJOI2015 骑士的旅行
- bzoj4336: BJOI2015 骑士的旅行
- 2017.10.6 BJOI2015 bzoj4337 树的同构
- 【Bzoj4336】骑士的旅行
- 2017.10.6 BJOI2015 bzoj4338 糖果
- bzoj4336: BJOI2015 骑士的旅行
- [树hash]BZOJ 4337——BJOI2015 树的同构
- 【BZOJ】4337 BJOI2015 树的同构 树hash
- [BZOJ4337][BJOI2015]树的同构(树的最小表示法)
- 【bzoj4337】【BJOI2015】【树的同构】【hash】
- BZOJ4340 : BJOI2015 隐身术
- BZOJ 4337: BJOI2015 树的同构
- 【BJOI2015】【BZOJ4337】树的同构
- 【BZOJ4337】BJOI2015 树的同构 括号序列
- BZOJ 4338 BJOI2015 糖果
- bzoj 4337: BJOI2015 树的同构 (树hash)
- 【Hash】bzoj4337 BJOI2015树的同构