[SPOJ-QTREE7]Query on a tree VII 题解
题目地址:洛谷:【SP16580】QTREE7 – Query on a tr …
May all the beauty be blessed.
题目地址:洛谷:【SP2939】QTREE5 – Query on a tree V – 洛谷、SPOJ:SPOJ.com – Problem QTREE5
SPOJ QTREE系列:
You are given a tree (an acyclic undirected connected graph) with N nodes. The tree nodes are numbered from 1 to N. We define dist(a, b) as the number of edges on the path from node a to node b.
Each node has a color, white or black. All the nodes are black initially.
We will ask you to perfrom some instructions of the following form:
给一棵树,最开始点都是黑色,操作1.改变点的颜色2.求离点v最近的白点距离。
输入格式:
In the first line there is an integer N (N <= 100000)
In the next N-1 lines, the i-th line describes the i-th edge: a line with two integers a b denotes an edge between a and b.
In the next line, there is an integer Q denotes the number of instructions (Q <= 100000)
In the next Q lines, each line contains an instruction “0 i” or “1 v”
输出格式:
For each “1 v” operation, print one integer representing its result. If there is no white node in the tree, you should write “-1”.
输入样例#1:
10 1 2 1 3 2 4 1 5 1 6 4 7 7 8 5 9 1 10 10 0 6 0 6 0 6 1 3 0 1 0 1 1 3 1 10 1 4 1 6
输出样例#1:
2 2 2 3 0
本题可以从QTREE4的边分写法改过来。
本题维护堆的方法与QTREE4类似。查询答案时,从该点对应的中心边从底向上查,离该点最近的白点肯定与其在同一子树中或者在被某一中心边分开的两个子树中,分别更新答案即可。由于我们将该点对应的所有中心边都找了一遍,因此不会存在在同一子树中却从更远的中心边绕了弯的情况,因为在更近的中心边已经更新了答案了。
// Code by KSkun, 2018/3
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <queue>
typedef long long LL;
inline char fgc() {
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
inline LL readint() {
register LL res = 0, neg = 1;
register char c = fgc();
while(c < '0' || c > '9') {
if(c == '-') neg = -1;
c = fgc();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = fgc();
}
return res * neg;
}
const int MAXN = 200005, INF = 2e9;
int n, q, col[MAXN], ans;
struct Edge {
int to, w, nxt;
} gra[MAXN << 1], grao[MAXN << 1];
int head[MAXN], heado[MAXN], ecnt, ecnto;
inline void addedge(int u, int v, int w) {
gra[ecnt] = Edge {v, w, head[u]}; head[u] = ecnt++;
}
inline void addedgeo(int u, int v, int w) {
grao[ecnto] = Edge {v, w, heado[u]}; heado[u] = ecnto++;
}
inline void rebuild(int u, int fa) {
int ff = 0;
for(int i = heado[u]; ~i; i = grao[i].nxt) {
int v = grao[i].to, w = grao[i].w;
if(v == fa) continue;
if(!ff) {
addedge(u, v, w);
addedge(v, u, w);
ff = u;
} else {
int k = ++n;
addedge(ff, k, 0);
addedge(k, ff, 0);
addedge(k, v, w);
addedge(v, k, w);
ff = k;
}
rebuild(v, u);
}
}
bool del[MAXN << 1];
int ct, ctsiz, sum;
int siz[MAXN], msz[MAXN];
inline void calsiz(int u, int fa) {
siz[u] = 1;
for(int i = head[u]; ~i; i = gra[i].nxt) {
int v = gra[i].to;
if(del[i >> 1] || v == fa) continue;
calsiz(v, u);
siz[u] += siz[v];
}
}
inline void findct(int u, int fa) {
for(int i = head[u]; ~i; i = gra[i].nxt) {
int v = gra[i].to;
if(del[i >> 1] || v == fa) continue;
findct(v, u);
int vsiz = std::max(siz[v], sum - siz[v]);
if(vsiz < ctsiz) {
ct = i;
ctsiz = vsiz;
}
}
}
struct DisData {
int u, d;
inline bool operator<(const DisData &rhs) const {
return d > rhs.d;
}
};
std::priority_queue<DisData> s[MAXN][2];
int cnt;
struct NodeData {
int bel, side, dis;
};
std::vector<NodeData> ndata[MAXN];
inline void caldis(int u, int fa, int d, int t, int l) {
ndata[u].push_back(NodeData {t, l, d});
for(int i = head[u]; ~i; i = gra[i].nxt) {
int v = gra[i].to, w = gra[i].w;
if(del[i >> 1] || v == fa) continue;
caldis(v, u, d + w, t, l);
}
}
int lch[MAXN], rch[MAXN], ctw[MAXN];
inline void update(int p) {
while(!s[p][0].empty() && !col[s[p][0].top().u]) s[p][0].pop();
while(!s[p][1].empty() && !col[s[p][1].top().u]) s[p][1].pop();
}
inline int divide(int u) {
calsiz(u, 0);
ct = -1; ctsiz = INF; sum = siz[u]; findct(u, 0);
if(ct == -1) return 0;
int x = gra[ct].to, y = gra[ct ^ 1].to;
del[ct >> 1] = true;
int t = ++cnt;
ctw[t] = gra[ct].w;
caldis(x, 0, 0, t, 0); caldis(y, 0, 0, t, 1);
lch[t] = divide(x); rch[t] = divide(y);
return t;
}
inline void setwhite(int u) {
for(int i = ndata[u].size() - 1; i >= 0; i--) {
NodeData d = ndata[u][i];
s[d.bel][d.side].push(DisData {u, d.dis});
update(d.bel);
}
}
inline void setblack(int u) {
for(int i = ndata[u].size() - 1; i >= 0; i--) {
NodeData d = ndata[u][i];
update(d.bel);
}
}
inline int query(int u) {
int mn = INF;
for(int i = ndata[u].size() - 1; i >= 0; i--) {
NodeData d = ndata[u][i];
if(!s[d.bel][d.side].empty()) mn = std::min(mn, s[d.bel][d.side].top().d + d.dis);
if(!s[d.bel][d.side ^ 1].empty()) mn = std::min(mn, s[d.bel][d.side ^ 1].top().d + d.dis + ctw[d.bel]);
}
return mn;
}
int op, ut, vt;
int main() {
memset(head, -1, sizeof(head));
memset(heado, -1, sizeof(heado));
n = readint();
int white = 0;
for(int i = 1; i < n; i++) {
ut = readint(); vt = readint();
addedgeo(ut, vt, 1);
addedgeo(vt, ut, 1);
}
rebuild(1, 0);
divide(1);
q = readint();
while(q--) {
op = readint();
ut = readint();
if(op == 1) {
if(!white) {
puts("-1");
} else if(col[ut]) {
puts("0");
} else {
printf("%d\n", query(ut));
}
} else {
col[ut] ^= 1;
if(!col[ut]) {
setblack(ut);
white--;
} else {
setwhite(ut);
white++;
}
}
}
return 0;
}
题目地址:洛谷:【SP1487】PT07J – Query on a tree III – 洛谷、SPOJ:SPOJ.com – Problem PT07J
SPOJ QTREE系列:
You are given a node-labeled rooted tree with n nodes.
Define the query (x, k): Find the node whose label is k-th largest in the subtree of the node x. Assume no two nodes have the same labels.
给一棵带点权的以1为根的有根树,查询某子树内点权第k小值。
输入格式:
The first line contains one integer n (1 <= n <= 105). The next line contains n integers li (0 <= li <= 109) which denotes the label of the i-th node.
Each line of the following n – 1 lines contains two integers u, v. They denote there is an edge between node u and node v. Node 1 is the root of the tree.
The next line contains one integer m (1 <= m <= 104) which denotes the number of the queries. Each line of the next m contains two integers x, k. (k <= the total node number in the subtree of x)
输出格式:
For each query (x, k), output the index of the node whose label is the k-th largest in the subtree of the node x.
输入样例#1:
5 1 3 5 2 7 1 2 2 3 1 4 3 5 4 2 3 4 1 3 2 3 2
输出样例#1:
5 4 5 5
DFS序+主席树。主席树的叶子节点可以存一下DFS序号,这样方便查。
// Code by KSkun, 2018/3
#include <cstdio>
#include <vector>
#include <algorithm>
typedef long long LL;
inline char fgc() {
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF
: *p1++;
}
inline LL readint() {
register LL res = 0, neg = 1;
register char c = fgc();
while(c < '0' || c > '9') {
if(c == '-') neg = -1;
c = fgc();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = fgc();
}
return res * neg;
}
const int MAXN = 100005;
std::vector<int> gra[MAXN];
int dfn[MAXN], ptn[MAXN], siz[MAXN], clk;
inline void dfs(int u, int fa) {
dfn[u] = ++clk;
ptn[dfn[u]] = u;
siz[u] = 1;
for(int v : gra[u]) {
if(v == fa) continue;
dfs(v, u);
siz[u] += siz[v];
}
}
struct SGT {
struct SGTNode {
int lch, rch, val, dfn;
} tr[MAXN * 20];
int rt[MAXN], cnt = 0;
inline void insert(int &o, int l, int r, int x, int dfn) {
tr[++cnt] = tr[o]; o = cnt;
tr[o].val++;
if(l == r) {
tr[o].dfn = dfn;
return;
}
int mid = (l + r) >> 1;
if(x <= mid) insert(tr[o].lch, l, mid, x, dfn);
else insert(tr[o].rch, mid + 1, r, x, dfn);
}
inline int query(int o1, int o2, int l, int r, int k) {
if(l == r) return ptn[tr[o2].dfn];
int mid = (l + r) >> 1;
if(k <= tr[tr[o2].lch].val - tr[tr[o1].lch].val) {
return query(tr[o1].lch, tr[o2].lch, l, mid, k);
} else {
k -= tr[tr[o2].lch].val - tr[tr[o1].lch].val;
return query(tr[o1].rch, tr[o2].rch, mid + 1, r, k);
}
}
} sgt;
int n, m, w[MAXN], ut, vt, xt, kt;
std::vector<int> tmp;
int main() {
n = readint();
tmp.push_back(-1);
for(int i = 1; i <= n; i++) {
w[i] = readint();
tmp.push_back(w[i]);
}
std::sort(tmp.begin(), tmp.end());
tmp.erase(std::unique(tmp.begin(), tmp.end()), tmp.end());
int N = tmp.size() - 1;
for(int i = 1; i <= n; i++) {
w[i] = std::lower_bound(tmp.begin(), tmp.end(), w[i]) - tmp.begin();
}
for(int i = 1; i < n; i++) {
ut = readint(); vt = readint();
gra[ut].push_back(vt);
gra[vt].push_back(ut);
}
dfs(1, 0);
for(int i = 1; i <= n; i++) {
sgt.rt[i] = sgt.rt[i - 1];
sgt.insert(sgt.rt[i], 1, N, w[ptn[i]], i);
}
m = readint();
while(m--) {
xt = readint(); kt = readint();
printf("%d\n", sgt.query(sgt.rt[dfn[xt] - 1], sgt.rt[dfn[xt] + siz[xt] - 1],
1, N, kt));
}
return 0;
}
题目地址:洛谷:【SP375】QTREE – Query on a tree – 洛谷、SPOJ:SPOJ.com – Problem QTREE
SPOJ QTREE系列:
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3…N-1.
We will ask you to perfrom some instructions of the following form:
给一棵带边权的树,操作1.改边权2.求路径上最大边权。
输入格式:
The first line of input contains an integer t, the number of test cases (t <= 20). t test cases follow.
For each test case:
There is one blank line between successive tests.
输出格式:
For each “QUERY” operation, write one integer representing its result.
输入样例#1:
1 3 1 2 1 2 3 2 QUERY 1 2 CHANGE 1 3 QUERY 1 2 DONE
输出样例#1:
1 3
考虑树链剖分,把每条边的权值记在较深的那个点上即可。剩下的就是板子。注意查询的时候LCA不能计算进去。
// Code by KSkun, 2018/3
#include <cstdio>
#include <cstring>
inline int max(int a, int b) {
return a > b ? a : b;
}
inline char fgc() {
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
inline int readint() {
register int res = 0, neg = 1;
register char c = fgc();
while(c < '0' || c > '9') {
if(c == '-') neg = -1;
c = fgc();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = fgc();
}
return res * neg;
}
inline bool isop(char c) {
return c == 'Q' || c == 'C' || c == 'D';
}
inline char readop() {
register char c;
while(!isop(c = fgc()));
return c;
}
const int MAXN = 10005;
struct Edge {
int to, w, nxt;
} gra[MAXN << 1];
int head[MAXN], tot;
int T, n, m, ut, vt, wt;
char op;
int w[MAXN], fa[MAXN], siz[MAXN], son[MAXN], dfn[MAXN], ptn[MAXN], top[MAXN], dep[MAXN], cnt;
inline void dfs1(int u) {
siz[u] = 1;
son[u] = 0;
for(register int i = head[u]; i; i = gra[i].nxt) {
register int v = gra[i].to;
if(v == fa[u]) continue;
dep[v] = dep[u] + 1;
fa[v] = u;
w[v] = gra[i].w;
dfs1(v);
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
inline void dfs2(int u, int tp) {
top[u] = tp;
dfn[u] = ++cnt;
ptn[dfn[u]] = u;
if(son[u]) dfs2(son[u], tp);
for(register int i = head[u]; i; i = gra[i].nxt) {
register int v = gra[i].to;
if(v == son[u] || v == fa[u]) continue;
dfs2(v, v);
}
}
int sgt[MAXN << 2];
inline void build(int o, int l, int r) {
if(l == r) {
sgt[o] = w[ptn[l]];
return;
}
register int mid = (l + r) >> 1, lch = o << 1, rch = (o << 1) | 1;
build(lch, l, mid);
build(rch, mid + 1, r);
sgt[o] = max(sgt[lch], sgt[rch]);
}
inline void modify(int o, int l, int r, int x, int v) {
if(l == r) {
sgt[o] = v;
return;
}
register int mid = (l + r) >> 1, lch = o << 1, rch = (o << 1) | 1;
if(x <= mid) modify(lch, l, mid, x, v);
else modify(rch, mid + 1, r, x, v);
sgt[o] = max(sgt[lch], sgt[rch]);
}
inline int query(int o, int l, int r, int ll, int rr) {
if(l >= ll && r <= rr) {
return sgt[o];
}
register int mid = (l + r) >> 1, lch = o << 1, rch = (o << 1) | 1, res = 0;
if(ll <= mid) res = max(res, query(lch, l, mid, ll, rr));
if(rr > mid) res = max(res, query(rch, mid + 1, r, ll, rr));
return res;
}
inline int query(int u, int v) {
register int res = 0, tu = top[u], tv = top[v], t;
while(tu != tv) {
if(dep[tu] > dep[tv]) {
t = tu; tu = tv; tv = t;
t = u; u = v; v = t;
}
res = max(res, query(1, 1, n, dfn[tv], dfn[v]));
v = fa[tv];
tv = top[v];
}
if(dep[u] > dep[v]) { t = u; u = v; v = t; }
if(u != v) res = max(res, query(1, 1, n, dfn[u] + 1, dfn[v]));
return res;
}
struct Edge1 {
int u, v, w;
} edge[MAXN];
int main() {
T = readint();
while(T--) {
tot = cnt = 0;
memset(head, 0, sizeof(head));
n = readint();
for(int i = 1; i < n; i++) {
ut = readint(); vt = readint(); wt = readint();
edge[i] = Edge1 {ut, vt, wt};
gra[++tot] = Edge {vt, wt, head[ut]};
head[ut] = tot;
gra[++tot] = Edge {ut, wt, head[vt]};
head[vt] = tot;
}
dfs1(1);
dfs2(1, 1);
build(1, 1, n);
for(;;) {
op = readop();
if(op == 'D') break;
ut = readint();
vt = readint();
if(op == 'Q') {
printf("%d\n", query(ut, vt));
} else {
register int u = dep[edge[ut].u] > dep[edge[ut].v] ? edge[ut].u : edge[ut].v;
modify(1, 1, n, dfn[u], vt);
}
}
}
return 0;
}