Spoj 375 QTREE1 树链剖分裸题

题目链接:http://www.spoj.com/problems/QTREE/

题意:

T个测试案例

n个点的树

下面n-1条边和边权

 

change u v 把第u-th给出的边 的边权改为v

query 询问路径 [u, v] 间最大的边权

 

 

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#define N 10010
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define Mid(x,y) ((x+y)>>1)
using namespace std;

struct Edge{
	int from, to, nex;
}edge[N<<1];
int head[N], edgenum;
void add(int u, int v){
	Edge E={u, v, head[u]}; edge[edgenum] = E;	head[u] = edgenum++;
}

int fa[N], siz[N], son[N], w[N], p[N], dep[N], tree_id;
int fp[N];//和p数组相反
//给每条边编号 边(u, v),设dep[u]<dep[v](v在下面) 用v来表示边的编号
//w[v] 表示v所在的父边 在线段树中的位置
void dfs(int u, int father, int deep){
	son[u] = 0; fa[u] = father; siz[u] = 1; dep[u] = deep;
	for(int i = head[u]; ~i; i = edge[i].nex){
		int v = edge[i].to;
		if(v == father)continue;
		dfs(v, u, deep+1);
		siz[u] += siz[v];
		if(siz[v] > siz[ son[u] ])son[u] = v;
	}
}

void Have_p(int u, int father){
	w[u] = ++tree_id; p[u] = father;
	if(son[u])
		Have_p(son[u], father);
	else return;
	for(int i = head[u]; ~i; i = edge[i].nex)
	{
		int v = edge[i].to;
		if(v != fa[u] && v != son[u])
		Have_p(v, v);
	}
}

struct node{
	int l, r;
	int Max;
}tree[N*4];

void build(int l, int r, int id){
	tree[id].l = l, tree[id].r = r;
	tree[id].Max = 0;
	if(l == r)return ;
	int mid = Mid(l,r);
	build(l, mid, L(id));
	build(mid+1, r, R(id));
}
void updata(int pos, int val, int id){
	if(tree[id].l == tree[id].r)
	{
		tree[id].Max = val;
		return ;
	}
	int mid = Mid(tree[id].l, tree[id].r);
	if(pos <= mid)
		updata(pos, val, L(id));
	else
		updata(pos, val, R(id));
	tree[id].Max = max(tree[L(id)].Max, tree[R(id)].Max);
}
int query(int l, int r, int id){
	if(l == tree[id].l && tree[id].r == r)
		return tree[id].Max;
	int mid = Mid(tree[id].l, tree[id].r);
	if(r<=mid)
		return query(l, r, L(id));
	else if(mid<l)
		return query(l, r, R(id));
	else
		return max(query(l, mid, L(id)), query(mid+1, r, R(id)));
}
int find(int u, int v){
	int f1 = p[u], f2 = p[v];
	int tmp = 0;
	while(f1 != f2)
	{
		if(dep[f1] < dep[f2])
			swap(f1, f2), swap(u, v);
		tmp = max(tmp, query(w[f1], w[u], 1));
		u = fa[f1], f1 = p[u];
	}
	if(u == v)return tmp;
	if(dep[u] > dep[v])swap(u, v);
	return max(tmp, query(w[son[u]], w[v], 1));
}


int n;
int D[N][3];
void init(){
	memset(head, -1, sizeof(head)); edgenum = 0;
	memset(son, 0, sizeof(son));//这个的初始化
	tree_id = 0;
}
int main(){
	int T;scanf("%d",&T);
	int i, u, v, d;
	char s[10];

	while(T--){
		scanf("%d",&n);
		init();
		for(i=1;i<n;i++)
		{
			scanf("%d %d %d", &u,&v,&d);
			D[i][0] = u, D[i][1] = v, D[i][2] = d;
			add(u, v),   add(v, u);
		}
		dfs(1, 1, 0);
		Have_p(1, 1);
		build(1, n, 1);
		for(i=1;i<n;i++)
		{
			//int u = D[i][0], v = D[i][1], d = D[i][2];
			//if(dep[u]>dep[v]) swap(u, v)因为 w[v] 是表示父边,显然是深度大的v才能表示父边
			if(dep[ D[i][0] ] > dep[ D[i][1] ])swap(D[i][0], D[i][1]);
			updata(w[ D[i][1] ], D[i][2], 1);
		}
		while(scanf("%s",s))
		{	 
			if(s[0] == 'D')break;
			scanf("%d %d", &u, &v);

			if(s[0] == 'C')
				updata(w[D[u][1]], v, 1);
			else
				printf("%d\n", find(u,v));
		}
	}
	return 0;
}


 

 

你可能感兴趣的:(Spoj 375 QTREE1 树链剖分裸题)