[BZOJ4317]Atm的树
[BZOJ4317]Atm的树
试题描述
Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree……
于是,一天晚上他梦到自己被关在了一个有根树中,每条路径都有边权,一个神秘的声音告诉他,每个点到其他的点有一个距离(什么是距离不用说吧),他需要对于每个点回答:从这个点出发的第k小距离是多少;
如果atm不能回答出来,那么明天4019的闹钟将不会响,4019全寝可能就迟到了,所以atm希望你帮帮他。
输入
第一行,两个正整数n,k,表示树的点数,询问的是第几小距离;
第二~n行,每行三个正整数x,y,w,表示x和y之间有一条边,x为父亲,边权为w;
输出
n行, 每行一个数,第i行输出从i开始第k小距离
输入示例
5 2 1 5 2 1 2 4 2 3 6 2 4 5
输出示例
4 5 10 9 6
数据规模及约定
100% n<=15000, 边权在1~10之间,为了方便,保证1为根;K<=5000
题解
参见这道题。
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *Tail; inline char Getchar() { if(Head == Tail) { int l = fread(buffer, 1, BufferSize, stdin); Tail = (Head = buffer) + l; } return *Head++; } int read() { int x = 0, f = 1; char c = Getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); } return x * f; } #define maxn 15010 #define maxm 30010 #define maxlog 15 int n, m, head[maxn], nxt[maxm], to[maxm], dist[maxm]; void AddEdge(int a, int b, int c) { to[++m] = b; dist[m] = c; nxt[m] = head[a]; head[a] = m; swap(a, b); to[++m] = b; dist[m] = c; nxt[m] = head[a]; head[a] = m; return ; } int mnd[maxlog][maxn<<1], Log[maxn<<1], clo, dep[maxn], dfn[maxn]; void build(int u, int pa) { mnd[0][dfn[u] = ++clo] = dep[u]; for(int e = head[u]; e; e = nxt[e]) if(to[e] != pa) dep[to[e]] = dep[u] + dist[e], build(to[e], u), mnd[0][++clo] = dep[u]; return ; } void rmq_init() { Log[1] = 0; for(int i = 2; i <= clo; i++) Log[i] = Log[i>>1] + 1; for(int j = 1; (1 << j) <= clo; j++) for(int i = 1; i + (1 << j) - 1 <= clo; i++) mnd[j][i] = min(mnd[j-1][i], mnd[j-1][i+(1<<j-1)]); return ; } int cdist(int a, int b) { int l = dfn[a], r = dfn[b]; if(l > r) swap(l, r); int t = Log[r-l+1]; return dep[a] + dep[b] - (min(mnd[t][l], mnd[t][r-(1<<t)+1]) << 1); } #define maxnode 1800010 struct Node { int v, r, siz; Node() {} Node(int _, int __): v(_), r(__) {} }; struct Treap { Node ns[maxnode]; int ToT, fa[maxnode], ch[maxnode][2]; void maintain(int o) { if(!o) return ; ns[o].siz = 1; for(int i = 0; i < 2; i++) if(ch[o][i]) ns[o].siz += ns[ch[o][i]].siz; return ; } void rotate(int u) { int y = fa[u], z = fa[y], l = 0, r = 1; if(z) ch[z][ch[z][1]==y] = u; if(ch[y][1] == u) swap(l, r); fa[u] = z; fa[y] = u; fa[ch[u][r]] = y; ch[y][l] = ch[u][r]; ch[u][r] = y; maintain(y); maintain(u); return ; } void Insert(int& o, int v) { if(!o) { ns[o = ++ToT] = Node(v, rand()); return maintain(o); } bool d = v > ns[o].v; Insert(ch[o][d], v); fa[ch[o][d]] = o; if(ns[ch[o][d]].r > ns[o].r) { int t = ch[o][d]; rotate(t); o = t; } return maintain(o); } int query(int o, int v) { if(!o) return 0; int ls = ch[o][0] ? ns[ch[o][0]].siz : 0; if(v < ns[o].v) return query(ch[o][0], v); return ls + 1 + query(ch[o][1], v); } } sol; int f[maxn], siz[maxn], rt, size; bool vis[maxn]; void getroot(int u, int pa) { siz[u] = 1; f[u] = 0; for(int e = head[u]; e; e = nxt[e]) if(to[e] != pa && !vis[to[e]]) { getroot(to[e], u); siz[u] += siz[to[e]]; f[u] = max(f[u], siz[to[e]]); } f[u] = max(f[u], size - siz[u]); if(f[rt] > f[u]) rt = u; return ; } void dfs(int u, int pa) { siz[u] = 1; for(int e = head[u]; e; e = nxt[e]) if(to[e] != pa && !vis[to[e]]) dfs(to[e], u), siz[u] += siz[to[e]]; return ; } int fa[maxn]; void solve(int u) { vis[u] = 1; for(int e = head[u]; e; e = nxt[e]) if(!vis[to[e]]) { dfs(to[e], u); f[rt = 0] = size = siz[to[e]]; getroot(to[e], u); fa[rt] = u; solve(rt); } return ; } int Rt[maxn], Rtfa[maxn]; void update(int s) { sol.Insert(Rt[s], 0); for(int u = s; fa[u]; u = fa[u]) { int d = cdist(s, fa[u]); // printf("insert:: %d(fa: %d): %d\n", u, fa[u], d); sol.Insert(Rtfa[u], d); sol.Insert(Rt[fa[u]], d); } return ; } int query(int s, int x) { int ans = sol.query(Rt[s], x); // printf("base: %d\n", ans); for(int u = s; fa[u]; u = fa[u]) { int d = cdist(s, fa[u]); // printf("query:: %d(fa: %d): %d (%d - %d)\n", u, fa[u], x - d, sol.query(Rt[fa[u]], x - d), sol.query(Rtfa[u], x - d)); ans += sol.query(Rt[fa[u]], x - d) - sol.query(Rtfa[u], x - d); } return ans; } int main() { n = read(); int K = read(), sum = 0; for(int i = 1; i < n; i++) { int a = read(), b = read(), c = read(); AddEdge(a, b, c); sum += c; } build(1, 0); rmq_init(); f[rt = 0] = size = n; getroot(1, 0); solve(rt); // for(int i = 1; i <= n; i++) printf("(%d)%d%c", i, fa[i], i < n ? ' ' : '\n'); for(int i = 1; i <= n; i++) update(i); for(int i = 1; i <= n; i++) { int l = 1, r = sum; while(l < r) { int mid = l + r >> 1; if(query(i, mid) - 1 < K) l = mid + 1; else r = mid; } printf("%d\n", l); } return 0; }
又 1A 啦 2333333!
双倍经验:BZOJ2051,改改数据范围。