被虐惨了QwQ
下面的程序只是备份并不是最终代码QwQ
连编译器都怕了我的代码QwQ
编译时间长于5s QwQ
#include <cstdio>
#include <algorithm>
#define FOR(i,j,k) for(int i=j;i<=k;++i)
using namespace std;
const int N = 200005, M = N * 2, K = 19;
typedef long long ll;
ll read() {
ll x = 0, f = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') x = x * 10 + ch - '0';
for (; '0' <= ch && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return x * f;
}
struct Seg {
Seg *lc, *rc; int sz;
Seg() { lc = rc = this; sz = 0; }
Seg(Seg *_lc, Seg *_rc, int _sz) :
lc(_lc), rc(_rc), sz(_sz) { }
void *operator new(size_t) {
static Seg p[M * 30], *C = p;
return C++;
}
Seg *put(int l, int r, int x) {
int mid = l + r >> 1;
if (l == r) return new Seg(0, 0, sz + 1);
else if (x <= mid) return new Seg(lc->put(l, mid, x), rc, sz + 1);
else return new Seg(lc, rc->put(mid + 1, r, x), sz + 1);
}
static int get(Seg *x, Seg *y, int l, int r, int k) {
int mid = l + r >> 1;
if (l == r) return l;
if (k <= y->lc->sz - x->lc->sz) return get(x->lc, y->lc, l, mid, k);
else return get(x->rc, y->rc, mid + 1, r, k - (y->lc->sz - x->lc->sz));
}
} *tree[N];
int n;
int query(int x, int y, int k) {
return Seg::get(tree[x - 1], tree[y], 1, n, k);
}
struct Tree {
int h[N], p[M], v[M], cnt, fa[N][20];
int pos[N], end[N], dep[N], id, sz[N];
ll w[M], dis[N];
void add(int a, int b, ll c) {
p[++cnt] = h[a]; v[cnt] = b; w[cnt] = c; h[a] = cnt;
p[++cnt] = h[b]; v[cnt] = a; w[cnt] = c; h[b] = cnt;
}
void dfs(int x, int f, ll d) {
fa[x][0] = f; dep[x] = dep[f] + 1; dis[x] = d;
FOR(i,1,K) fa[x][i] = fa[fa[x][i - 1]][i - 1];
for (int i = h[x]; i; i = p[i])
if (v[i] != f) dfs(v[i], x, d + w[i]);
}
void dfs2(int x) {
sz[x] = 1; pos[x] = ++id; tree[id] = tree[id - 1]->put(1, n, x);
for (int i = h[x]; i; i = p[i])
if (v[i] != fa[x][0])
dfs2(v[i]), sz[x] += sz[v[i]];
end[x] = id;
}
int jump(int x, int d) {
FOR(i,0,K) if ((1 << i) & d) x = fa[x][i];
return x;
}
int lca(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
jump(x, dep[x] - dep[y]);
for(int i=K;i>=0;--i) if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return x == y ? x : fa[x][0];
}
ll dist(int x, int y) {
return dis[x] + dis[y] - 2 * dis[lca(x, y)];
}
int belong(int u, int v) {
return jump(u, dep[u] - dep[v] - 1);
}
} o, g;
int rt[N], belong[N], idx; ll cnt[N], nn;
int id(ll x) { return lower_bound(cnt + 1, cnt + 1 + idx, x) - cnt; }
ll query(ll a, ll b) {
ll A = a, B = b;
a = id(a); b = id(b);
int c = g.lca(a, b);
int ra = rt[a], rb = rt[b];
int aa = query(o.pos[ra], o.end[ra], A - cnt[a - 1]);
int bb = query(o.pos[rb], o.end[rb], B - cnt[b - 1]);
if (a == b) return o.dist(aa, bb);
ll ans = g.dist(a, b) + o.dis[aa] - o.dis[ra] + o.dis[bb] - o.dis[rb];
int fa = belong[g.belong(a, c)], fb = belong[g.belong(b, c)];
if (a == c) ans -= o.dis[aa] + o.dis[fb] - o.dist(aa, fb) - 2ll * o.dis[ra];
else if (b == c) ans -= o.dis[bb] + o.dis[fa] - o.dist(bb, fa) - 2ll * o.dis[rb];
else ans -= o.dis[fa] + o.dis[fb] - o.dist(fa, fb) - 2ll * o.dis[rt[c]];
return ans;
}
int main() {
int a, b, m, q, x, t;
n = read(); m = read(); q = read();
tree[0] = new Seg();
FOR(i,2,n) o.add(read(), read(), 1);
o.dfs(1, 0, 0); o.dfs2(1);
nn = n; cnt[1] = nn; rt[1] = idx = 1;
FOR(i,2,m+1) {
a = read(); b = read();
x = id(b); t = rt[x];
rt[i] = a; idx = i; belong[i] = query(o.pos[t], o.end[t], b - cnt[x - 1]);
g.add(i, x, o.dis[belong[i]] - o.dis[t] + 1);
nn += o.sz[a]; cnt[i] = nn;
}
g.dfs(1, 0, 0);
while (q--) printf("%lld\n", query(read(), read()));
return 0;
}
4539: [Hnoi2016]树
Description
小A想做一棵很大的树,但是他手上的材料有限,只好用点小技巧了。开始,小A只有一棵结点数为N的树,结
点的编号为1,2,…,N,其中结点1为根;我们称这颗树为模板树。小A决定通过这棵模板树来构建一颗大树。构建过
程如下:(1)将模板树复制为初始的大树。(2)以下(2.1)(2.2)(2.3)步循环执行M次(2.1)选择两个数字a,b,
其中1<=a<=N,1<=b<=当前大树的结点数。(2.2)将模板树中以结点a为根的子树复制一遍,挂到大树中结点b的下
方(也就是说,模板树中的结点a为根的子树复制到大树中后,将成为大树中结点b的子树)。(2.3)将新加入大树
的结点按照在模板树中编号的顺序重新编号。例如,假设在进行2.2步之前大树有L个结点,模板树中以a为根的子
树共有C个结点,那么新加入模板树的C个结点在大树中的编号将是L+1,L+2,…,L+C;大树中这C个结点编号的大小
顺序和模板树中对应的C个结点的大小顺序是一致的。下面给出一个实例。假设模板树如下图:
根据第(1)步,初始的大树与模板树是相同的。在(2.1)步,假设选择了a=4,b=3。运行(2.2)和(2.3)后,得到新的
大树如下图所示
现在他想问你,树中一些结点对的距离是多少。
Input
第一行三个整数:N,M,Q,以空格隔开,N表示模板树结点数,M表示第(2)中的循环操作的次数,Q 表示询问数
量。接下来N-1行,每行两个整数 fr,to,表示模板树中的一条树边。再接下来M行,每行两个整数x,to,表示将模
板树中 x 为根的子树复制到大树中成为结点to的子树的一次操作。再接下来Q行,每行两个整数fr,to,表示询问
大树中结点 fr和 to之间的距离是多少。
Output
输出Q行,每行一个整数,第 i行是第 i个询问的答案。
Sample Input
5 2 3
1 4
1 3
4 2
4 5
4 3
3 2
6 9
1 8
5 3
Sample Output
6
3
3
HINT
经过两次操作后,大树变成了下图所示的形状:
结点6到9之间经过了6条边,所以距离为6;类似地,结点1到8之间经过了3条边;结点5到3之间也经过了3条边。