【SPOJ】375. Query on a tree(树链剖分)

本文分享了SPoj QTREE问题的解决方案,作者通过调试和数据对比,最终解决了边分类问题,并提供了完整的代码示例。文章详细记录了从发现错误到修复的过程,强调了在处理父子节点关系时需要注意的细节。

http://www.spoj.com/problems/QTREE/

这是按边分类的。

调试调到吐,对拍都查不出来,后来改了下造数据的,拍出来了。囧啊啊啊啊啊啊

时间都花在调试上了,打hld只用了半小时啊囧。

第一次打边分类真没注意一个地方。

就是当fx==fy后,没有判断x==y,然后这是边分类,获得的是父亲的下标,果断错。。

囧,一定要记住这个错误。

#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;
#define lc x<<1
#define rc x<<1|1
#define lson l, m, lc
#define rson m+1, r, rc
#define MID (l+r)>>1
#define read(x) x=getint()
#define dbg(x) cout << #x << "=" << x << endl
inline const int max(const int& a, const int& b) { return a>b?a:b; }
inline int getint() { char c; int ret=0, k=1; for(c=getchar(); c<'0' || c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0' && c<='9'; c=getchar()) ret=ret*10+c-'0'; return k*ret; }

const int N=50010, oo=~0u>>1;
struct Ed { int u, v, w; }e[N];
int ihead[N], inext[N<<1], to[N<<1], cnt;
int fa[N], sz[N], son[N], top[N], dep[N], id[N], mx[N*5], num[N], tot, L, R, key, n;

inline void pushup(const int &x) { mx[x]=max(mx[lc], mx[rc]); }
void build(const int &l, const int &r, const int &x) {
	if(l==r) { mx[x]=num[l]; return; }
	int m=MID;
	build(lson); build(rson);
	pushup(x); 
}
void update(const int &l, const int &r, const int &x) {
	if(l==r) { mx[x]=key; return; }
	int m=MID;
	if(L<=m) update(lson); if(m<R) update(rson); pushup(x);
}
int getmax(const int &l, const int &r, const int &x) {
	if(L<=l && r<=R) return mx[x];
	int m=MID, ret=oo+1;
	if(L<=m) ret=max(ret, getmax(lson)); if(m<R) ret=max(ret, getmax(rson)); return ret;
}
void dfs1(const int &u) {
	sz[u]=1; int v;
	for(int i=ihead[u]; i; i=inext[i]) if(fa[u]!=(v=to[i])) {
		fa[v]=u; dep[v]=dep[u]+1;
		dfs1(v);
		sz[u]+=sz[v];
		if(sz[v]>sz[son[u]]) son[u]=v;
	}
}
void dfs2(const int &u, const int &tp) {
	id[u]=++tot; top[u]=tp;
	if(son[u]) dfs2(son[u], tp);
	for(int i=ihead[u]; i; i=inext[i]) if(fa[u]!=to[i] && to[i]!=son[u]) dfs2(to[i], to[i]);
}
inline int getmax(int x, int y) {
	int fx=top[x], fy=top[y], ret=oo+1;
	while(fx!=fy) {
		if(dep[fx]<dep[fy]) { swap(x, y); swap(fx, fy); }
		L=id[fx]; R=id[x];
		ret=max(ret, getmax(2, n, 1));
		x=fa[fx]; fx=top[x];
	}
	if(dep[x]>dep[y]) swap(x, y);
	if(x!=y) L=id[x]+1; R=id[y]; //这里,如果不特判的话,L会>R,然后线段树那里果断死循环
	return max(ret, getmax(2, n, 1));
}
inline void add(const int &u, const int &v) {
	inext[++cnt]=ihead[u]; ihead[u]=cnt; to[cnt]=v;
	inext[++cnt]=ihead[v]; ihead[v]=cnt; to[cnt]=u;
}
int main() {
	int c=getint(), a, b; char ch;
	while(c--) {
		read(n);
		tot=cnt=0;
		memset(ihead, 0, sizeof(int)*(n+10));
		memset(fa, 0, sizeof(int)*(n+10));
		memset(son, 0, sizeof(int)*(n+10));
		for(int i=1; i<n; ++i) {
			read(e[i].u); read(e[i].v); read(e[i].w);
			add(e[i].u, e[i].v);
		}
		dfs1(1); dfs2(1, 1);
		for(int i=1; i<n; ++i) {
			if(dep[e[i].u]>dep[e[i].v]) swap(e[i].u, e[i].v);
			num[id[e[i].v]]=e[i].w;
		}
		build(2, n, 1);
		for(ch=getchar(); ch<'A' || ch>'Z'; ch=getchar());
		while(ch!='D') {
			read(a); read(b);
			if(ch=='C') { key=b; L=R=id[e[a].v]; update(2, n, 1); }
			else printf("%d\n", getmax(a, b));
			for(ch=getchar(); ch<'A' || ch>'Z'; ch=getchar());
		}
	}
	return 0;	
}

 

 


 

 

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:

  • CHANGE i ti : change the cost of the i-th edge to ti
    or
  • QUERY a b : ask for the maximum edge cost on the path from node a to node b

Input

The first line of input contains an integer t, the number of test cases (t <= 20). t test cases follow.

For each test case:

  • In the first line there is an integer N (N <= 10000),
  • In the next N-1 lines, the i-th line describes the i-th edge: a line with three integers a b c denotes an edge between a, b of cost c (c <= 1000000),
  • The next lines contain instructions "CHANGE i ti" or "QUERY a b",
  • The end of each test case is signified by the string "DONE".

There is one blank line between successive tests.

Output

For each "QUERY" operation, write one integer representing its result.

Example

Input:
1

3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE

Output:
1
3

转载于:https://www.cnblogs.com/iwtwiioi/p/3923507.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值