【QTREE】子杰树 线段树+树链剖分

【题目大意】

给定一棵n个结点的树,树的边上有权。你被要求支持:

1.修改一条边上的权值。

2.查询两个结点x和y之间的最短路径中经过的最大的边的权值。

其中n<=10^4.

【题解】
树链剖分的模板题,我早就写过了,但长时间没做树剖的题目,这个模板已经忘得差不多了,今天再做用来复习树剖,顺便卡卡常数。
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define FILE "read"
#define MAXN 10010
#define up(i,j,n) for(int i=j;i<=n;++i)
#define dn(i,j,n) for(int i=j;i>=n;--i)
#define cmax(a,b) a=max(a,b)
#define cmin(a,b) a=min(a,b)
namespace INIT{
	char buf[1<<15],*fs,*ft;
	inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
	inline int read(){
		int x=0,f=1;  char ch=getchar();
		while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();}
		while(isdigit(ch))  {x=x*10+ch-'0';  ch=getchar();}
		return x*f;
	}
}using namespace INIT;
struct node{int y,next,v;}e[MAXN<<1];
int T,n,len,root,z,Link[MAXN],size[MAXN],son[MAXN],deep[MAXN],tr[MAXN*100],w[MAXN],f[MAXN],top[MAXN],d[MAXN][3];
void insert(int x,int y,int v){e[++len].next=Link[x];Link[x]=len;e[len].y=y;e[len].v=v;}
void dfs1(int x){
	size[x]=1;  son[x]=0;
	for(int i=Link[x];i;i=e[i].next){
		if(e[i].y==f[x])  continue;
		f[e[i].y]=x;  deep[e[i].y]=deep[x]+1;
		dfs1(e[i].y);
		size[x]+=size[e[i].y];
		if(size[e[i].y]>size[son[x]])  son[x]=e[i].y;
	}
}
void dfs2(int x,int temp){
	w[x]=++z;  top[x]=temp;
	if(son[x])  dfs2(son[x],temp);
	for(int i=Link[x];i;i=e[i].next) 
		if(e[i].y!=f[x]&&e[i].y!=son[x])  dfs2(e[i].y,e[i].y);
}
void updata(int p,int l,int r,int x,int v){
	if(x>r||x>1;
	updata(p<<1,l,mid,x,v);  updata(p<<1|1,mid+1,r,x,v);
	tr[p]=max(tr[p<<1],tr[p<<1|1]);
}
int maxi(int p,int l,int r,int x,int y){
	if(x>r||y=r)  return tr[p];
	int mid=(l+r)>>1;
	return max(maxi(p<<1,l,mid,x,y),maxi(p<<1|1,mid+1,r,x,y));
}
int find(int x,int y){
	int f1=top[x],f2=top[y],temp(0);
	while(f1!=f2){
		if(deep[f1]deep[y])  swap(x,y);
	return max(temp,maxi(1,1,z,w[son[x]],w[y]));
}
void init(){
	n=read();  root=(n+1)>>1;
	len=z=f[root]=deep[root]=0;
	memset(Link,0,sizeof(Link));
	memset(tr,0,sizeof(tr));
	memset(size,0,sizeof(size));
	up(i,1,n-1){
		d[i][0]=read(),d[i][1]=read(),d[i][2]=read();
		insert(d[i][0],d[i][1],d[i][2]);
		insert(d[i][1],d[i][0],d[i][2]);
	}
	dfs1(root);  dfs2(root,root);
	up(i,1,n-1){
		if(deep[d[i][0]]>deep[d[i][1]])  swap(d[i][0],d[i][1]);
		updata(1,1,z,w[d[i][1]],d[i][2]);
	}
}
void work(){
	char ch[10];
	while(~scanf("%s",ch)){
		if(ch[0]=='Q')  {int x=read(),y=read();  printf("%d\n",find(x,y));}
		else if(ch[0]=='C')  {int x=read(),v=read();  updata(1,1,z,w[d[x][1]],v);}
		else break;
	}
}
int main(){
	freopen(FILE".in","r",stdin);
	freopen(FILE".out","w",stdout);
	T=read();
	while(T--)  {init();  work();}
	return 0;
}


你可能感兴趣的:(线段树,树链剖分)