题目链接:SPOJ - QTREE
题意:一棵树,N个结点,任意次操作。
操作Change :a,b 将第a条边的权值改为b;
操作Query:a,b 查询结点a->b路径上的最大边权。
这是一道很裸的关于边操作的树链剖分题目,不多说了,直接上代码。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 10005
#define inf 0x3f3f3f3f
using namespace std;
struct node
{
int u,v,w,next;
}edge[N<<1];
int T,n,a,b,c;
char op[10];
int pre[N],cnt;
int son[N],dep[N],tid[N];
int top[N],fa[N],siz[N],id;
int maxx[N<<2];
int e[N][3];
void init()
{
cnt = id = 0;
memset(pre, -1, sizeof(pre));
memset(maxx, -inf, sizeof(maxx));
memset(siz, 0, sizeof(siz));
}
void addEdge(int u, int v, int w)
{
edge[cnt].u = u;
edge[cnt].v = v;
edge[cnt].next = pre[u];
pre[u] = cnt++;
}
void dfs1(int u, int f, int dp)
{
dep[u] = dp;
fa[u] = f;
siz[u] = 1;
son[u] = 0;
for(int i = pre[u]; ~i; i=edge[i].next)
{
int v = edge[i].v;
if(v != f)
{
dfs1(v, u, dp+1);
siz[u] += siz[v];
if(siz[v] > siz[son[u]])
son[u] = v;
}
}
}
void dfs2(int u, int tp)
{
top[u] = tp;
tid[u] = ++id;
if(son[u] == 0)return ;
dfs2(son[u], tp);
for(int i = pre[u]; ~i; i=edge[i].next)
{
int v = edge[i].v;
if(v != son[u] && v != fa[u])
dfs2(v, v);
}
}
void update(int rt, int l, int r, int pos, int w)
{
if(l == r && l == pos)
{
maxx[rt] = w;
return ;
}
int mid = (l + r) >> 1;
if(pos <= mid)
update(rt<<1, l, mid, pos, w);
else update(rt<<1|1, mid+1, r, pos, w);
maxx[rt] = max(maxx[rt<<1], maxx[rt<<1|1]);
}
int query(int rt, int l, int r, int ql, int qr)
{
if(ql <= l && r <= qr)
return maxx[rt];
int mid = (l + r) >> 1;
if(qr <= mid)
return query(rt<<1, l, mid, ql, qr);
if(ql > mid)
return query(rt<<1|1, mid+1, r, ql, qr);
return max(query(rt<<1, l, mid, ql, qr), query(rt<<1|1, mid+1, r, ql, qr));
}
int get(int x, int y)
{
int ans = -inf;
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]])
swap(x, y);
//if(top[x]==x)
ans = max(ans, query(1, 2, n, tid[top[x]], tid[x]));
//else ans = max(ans, query(1, 2, n, tid[top[x]]+1, tid[x]));
x = fa[top[x]];
}
if(x != y)
{
if(dep[x] > dep[y])
swap(x, y);
ans = max(ans, query(1, 2, n, tid[x]+1, tid[y]));
}
return ans;
}
void deal()
{
dfs1(1, 1, 1);
dfs2(1, 1);
for(int i = 1; i < n; ++i)
{
if(dep[e[i][0]] > dep[e[i][1]])
swap(e[i][0], e[i][1]);
update(1, 2, n, tid[e[i][1]], e[i][2]);
}
}
int main()
{
scanf("%d", &T);
while(T--)
{
init();
scanf("%d", &n);
for(int i = 1; i < n; ++i)
{
scanf("%d%d%d", &a,&b,&c);
addEdge(a, b, c);
addEdge(b, a, c);
e[i][0] = a,e[i][1] = b,e[i][2] = c;
}
deal();
while(~scanf("%s", op) && op[0]!='D')
{
scanf("%d%d", &a,&b);
if(op[0] == 'Q')
printf("%d\n", get(a, b));
else
update(1, 2, n, tid[e[a][1]], b);
}
}
return 0;
}
本文介绍了一道经典的树链剖分题目,通过详细的代码解释了如何处理树中边的操作,包括更新边权和查询路径最大权值。适用于对树链剖分算法有一定了解并希望深入理解其实现细节的读者。
639

被折叠的 条评论
为什么被折叠?



