SPOJ 375 Query on a tree

Desciption

给出一个树,每条边有边权,支持两种操作,询问 \(u,v\) 路径上边权最大值,修改第 \(i\) 条边的边权,\(n\leqslant 10^4,T\leqslant 10\)

Sol

树链剖分.

基于边的树链剖分,对于一个点,可能有许多儿子,但是它只能有一个父亲,给它编号表示它到它父亲的边,只需要修改查询的是最后一步就可以了.

Code

#include<cstdio>
#include<vector>
#include<iostream>
using namespace std;

#define debug(a) cout<<#a<<"="<<a<<" "
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc (o<<1|1)
const int N = 10005;

inline int in(int x=0,char ch=getchar()){ while(ch>‘9‘||ch<‘0‘) ch=getchar();
	while(ch>=‘0‘&&ch<=‘9‘) x=(x<<3)+(x<<1)+ch-‘0‘,ch=getchar();return x; }

int n,e,cnt;
struct Edge{ int fr,to,v; }edge[N];
vector<Edge> g[N];
int f[N],cost[N],dep[N],son[N],top[N],sz[N],p[N];
int d[N<<2];

void Add_Edge(int fr,int to,int v){
	edge[++e]=(Edge){ fr,to,v };
	g[fr].push_back((Edge){ fr,to,v });
	g[to].push_back((Edge){ to,fr,v });
}
void DFS1(int u,int fa){
	sz[u]=1,son[u]=0,dep[u]=dep[fa]+1,f[u]=fa;
	for(int i=0,lim=g[u].size(),v;i<lim;i++) if((v=g[u][i].to)!=fa){
		DFS1(v,u),sz[u]++;
		if(!son[u]||sz[son[u]]<sz[v]) son[u]=v;
	}
}
void DFS2(int u,int tp){
	p[u]=++cnt,top[u]=tp;
	if(son[u]) DFS2(son[u],tp);
	for(int i=0,lim=g[u].size(),v;i<lim;i++) if((v=g[u][i].to)!=f[u]&&v!=son[u])
		DFS2(v,v);
}
void Build(int o,int l,int r){
	if(l==r){ d[o]=cost[l];return; }
	Build(lc,l,mid),Build(rc,mid+1,r);
	d[o]=max(d[lc],d[rc]);
}
void Change(int o,int l,int r,int x,int v){
	if(l==r){ d[o]=v;return; }
	if(x<=mid) Change(lc,l,mid,x,v);
	else Change(rc,mid+1,r,x,v);
	d[o]=max(d[lc],d[rc]);
}
int QueryMax(int o,int l,int r,int L,int R){
	if(L<=l&&r<=R) return d[o];int res=0;
	if(L<=mid) res=max(res,QueryMax(lc,l,mid,L,R));
	if(R>mid) res=max(res,QueryMax(rc,mid+1,r,L,R));
	return res;
}
int GetAns(int u,int v){
	int res=0,f1=top[u],f2=top[v];
	while(f1!=f2){
		if(dep[f1]<dep[f2]) swap(u,v),swap(f1,f2);
		res=max(res,QueryMax(1,1,n,p[f1],p[u]));
		u=f[f1],f1=top[u];
	}
	if(dep[u]>dep[v]) swap(u,v);
	if(dep[v]==dep[u]) return res;
	else return max(res,QueryMax(1,1,n,p[u]+1,p[v]));
}
void clr(){ for(int i=0;i<N;i++) g[i].clear();cnt=0,e=0; }

int main(){
//	freopen("in.in","r",stdin);
//	freopen("out.out","w",stdout);
	ios::sync_with_stdio(false);
	for(int T=in();T--;){
		clr();
		n=in();
		for(int i=1,a,b,c;i<n;i++) a=in(),b=in(),c=in(),Add_Edge(a,b,c);
		DFS1(1,1),DFS2(1,1);

		for(int i=1;i<n;i++){
			int a=edge[i].fr,b=edge[i].to;
			if(dep[a]>dep[b]) swap(a,b),swap(edge[i].fr,edge[i].to);
			cost[p[b]]=edge[i].v;
		}

		Build(1,1,n);
		for(char opt[10];;){
			scanf("%s",opt);
			if(opt[0]==‘D‘) break;
			int a=in(),b=in();
			if(opt[0]==‘C‘) Change(1,1,n,p[edge[a].to],b);
			else printf("%d\n",GetAns(a,b));
//			debug(QueryMax(1,1,n,1,1)),debug(QueryMax(1,1,n,2,2)),debug(QueryMax(1,1,n,3,3))<<endl;
		}
	}return 0;
}

  

时间: 2024-08-28 13:47:51

SPOJ 375 Query on a tree的相关文章

spoj 375. Query on a tree 【树链剖分--插点问线 】

题目:spoj 375. Query on a tree 题意:题意很清晰,就是给你一颗树,每两点之间有权值,然后改变一些权值,问一条路径上的最大值. 分析:入门题目,直接套树链模板 AC代码: #include <cstdio> #include <algorithm> #include <iostream> #include <string.h> using namespace std; const int N = 10010; #define Del(

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

Query on a tree Time Limit: 5000ms Memory Limit: 262144KB This problem will be judged on SPOJ. Original ID: QTREE64-bit integer IO format: %lld      Java class name: Main Prev Submit Status Statistics Discuss Next Font Size: + - Type:   None Graph Th

spoj 375 Query on a tree (树链剖分)

Query on a tree 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 Q

spoj 375 query on a tree LCT

这道题是树链剖分的裸题,正在学LCT,用LCT写了,发现LCT代码比树链剖分还短点(但我的LCT跑极限数据用的时间大概是kuangbin大神的树链剖分的1.6倍,所以在spoj上是850ms卡过的). 收获: 1.边转换成点(即若存在边(u,v),则新加一个点z代表边,将z连接u和v,z的点权就是(u,v)的边权,非边点的权设为-oo),然后对边权的统计就变成了对点权的统计(这是LCT中处理边信息的通法之一). 2.若要连接两个点u,v,先让它们分别称为根,然后将其中一个的path-parent

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

题目大意:给你一棵树,有两个操作1.修改一条边的值,2.询问从x到y路径上边的最大值 思路:如果树退化成一条链的话线段树就很明显了,然后这题就是套了个树连剖分,调了很久终于调出来第一个模板了 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define maxn 100009 5 using namespace std; 6 int head[maxn],next[maxn*2],point[

spoj 375 query on a tree 题解

题目大意:维护一棵树,支持查询两点间路径最大值,以及修改某边的权值. 裸的树链剖分+线段树..不多说 这题卡常数卡的厉害啊!vector完全过不了 然后..我就写了我一点都不熟悉的普通邻接表. 虽然代码丑,虽然依然很慢,虽然有点长,但是它至少A了.. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 const int INF=~0U>&g

SPOJ QTREE 375. Query on a tree

SPOJ Problem Set (classical) 375. Query on a tree Problem code: 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: CHA

SPOJ - QTREE 375 Query on a tree 树链剖分+线段树

操作1:修改第k条边权. 操作2:询问两点间最大边权. 树链剖分,然后线段树维护最大值 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #inclu

SPOJ QTREE2 Query on a tree II

Query on a tree II Time Limit: 2000ms Memory Limit: 262144KB This problem will be judged on SPOJ. Original ID: QTREE264-bit integer IO format: %lld      Java class name: Main You are given a tree (an undirected acyclic connected graph) with N nodes,