2017.10.6 BJOI2015 bzoj4336 骑士的旅行

来源:互联网 发布:零基础学淘宝美工难吗 编辑:程序博客网 时间:2024/05/22 11:34
 骑士的旅行

题目背景:

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;}