POJ3237 Tree 树链剖分 线段树

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - POJ3237


题意概括

Description

给你由N个结点组成的树。树的节点被编号为1到N,边被编号为1到N-1。每一条边有一个权值。然后你要在树上执行一系列指令。指令可以是如下三种之一:
CHANGE i v:将第i条边的权值改成v。
NEGATE a b:将点a到点b路径上所有边的权值变成其相反数。
QUERY a b:找出点a到点b路径上各边的最大权值。

Input
多组数据,数据为T<=20,对于每组数据:
第一行有一个整数N(N<=10000)。
接下来N-1行每行有三个整数a,b,c,代表点a和点b之间有一条权值为c的边。这些边按照其编号从小到大给出。
接下来是若干条指令(不超过10^5条),都按照上面所说的格式。
最后一行是"DONE".

Output
对每个“QUERY”指令,输出一行,即路径上各边的最大权值。

Sample Input
1
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE

Sample Output
1
3


题解

  树链剖分+线段树单点修改、区间修改、区间询问。

  对于取相反数的,我们只需要维护一个最大值,一个最小值,然后打一下懒标记就可以了。

  在下传的时候,最大值反一反一定是最小的,最小值反一反一定是最大的,然后就好办了。


代码

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
using namespace std;
const int N=10005;
struct Edge{
	int cnt,y[N*2],z[N*2],nxt[N*2],fst[N];
	void clear(){
		cnt=0;
		memset(fst,0,sizeof fst);
	}
	void add(int a,int b,int c){
		y[++cnt]=b,z[cnt]=c,nxt[cnt]=fst[a],fst[a]=cnt;
	}
}g;
struct edge{
	int a,b,c;
}e[N];
int T,n,fa[N],size[N],fadis[N],depth[N],son[N],top[N],p[N],ap[N],cnp;
struct Tree{
	int ma,mi,add;
}t[N*4];
void Get_Gen_Info(int rt,int pre,int d){
	depth[rt]=d,fa[rt]=pre,size[rt]=1,son[rt]=-1;
	for (int i=g.fst[rt];i;i=g.nxt[i])
		if (g.y[i]!=pre){
			int s=g.y[i];
			Get_Gen_Info(s,rt,d+1);
			fadis[s]=g.z[i];
			size[rt]+=size[s];
			if (son[rt]==-1||size[s]>size[son[rt]])
				son[rt]=s;
		}
}
void Get_Pos(int rt,int tp){
	top[rt]=tp,p[rt]=++cnp,ap[cnp]=rt;
	if (son[rt]==-1)
		return;
	else
		Get_Pos(son[rt],tp);
	for (int i=g.fst[rt];i;i=g.nxt[i]){
		int s=g.y[i];
		if (s!=fa[rt]&&s!=son[rt])
			Get_Pos(s,s);
	}
}
void pushup(int rt){
	int ls=rt<<1,rs=ls|1;
	t[rt].mi=min(t[ls].mi,t[rs].mi);
	t[rt].ma=max(t[ls].ma,t[rs].ma);
}
void build(int rt,int le,int ri){
	t[rt].add=0;
	if (le==ri){
		t[rt].ma=t[rt].mi=fadis[ap[le]];
		return;
	}
	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
	build(ls,le,mid);
	build(rs,mid+1,ri);
	pushup(rt);
}
void fz(int &x,int &y){
	x=-x,y=-y;
	swap(x,y);
}
void pushdown(int rt){
	int &a=t[rt].add;
	int ls=rt<<1,rs=ls|1;
	if (a==0)
		return;
	t[ls].add^=1,t[rs].add^=1;
	fz(t[ls].ma,t[ls].mi);
	fz(t[rs].ma,t[rs].mi);
	a=0;
}
void change(int rt,int le,int ri,int pos,int v){
	if (le==ri){
		t[rt].mi=t[rt].ma=v;
		return;
	}
	pushdown(rt);
	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
	if (pos<=mid)
		change(ls,le,mid,pos,v);
	else
		change(rs,mid+1,ri,pos,v);
	pushup(rt);
}
void update(int rt,int le,int ri,int xle,int xri){
	if (le>xri||ri<xle)
		return;
	if (xle<=le&&ri<=xri){
		t[rt].add^=1;
		fz(t[rt].ma,t[rt].mi);
		return;
	}
	pushdown(rt);
	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
	update(ls,le,mid,xle,xri);
	update(rs,mid+1,ri,xle,xri);
	pushup(rt);
}
int query(int rt,int le,int ri,int xle,int xri){
	if (le>xri||ri<xle)
		return -1e9;
	if (xle<=le&&ri<=xri)
		return t[rt].ma;
	pushdown(rt);
	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
	return max(query(ls,le,mid,xle,xri),query(rs,mid+1,ri,xle,xri));
}
void fupdate(int a,int b){
	int f1=top[a],f2=top[b];
	while (f1!=f2){
		if (depth[f1]<depth[f2])
			swap(f1,f2),swap(a,b);
		update(1,1,n,p[f1],p[a]);
		a=fa[f1],f1=top[a];
	}
	if (a==b)
		return;
	if (depth[a]>depth[b])
		swap(a,b);
	update(1,1,n,p[son[a]],p[b]);
}
int find(int a,int b){
	int f1=top[a],f2=top[b],ans=-1e9;
	while (f1!=f2){
		if (depth[f1]<depth[f2])
			swap(f1,f2),swap(a,b);
		ans=max(ans,query(1,1,n,p[f1],p[a]));
		a=fa[f1],f1=top[a];
	}
	if (a==b)
		return ans;
	if (depth[a]>depth[b])
		swap(a,b);
	return max(ans,query(1,1,n,p[son[a]],p[b]));
}
int main(){
	scanf("%d",&T);
	while (T--){
		scanf("%d",&n);
		g.clear();
		for (int i=1,a,b,c;i<n;i++){
			scanf("%d%d%d",&a,&b,&c);
			g.add(a,b,c);
			g.add(b,a,c);
			e[i].a=a,e[i].b=b,e[i].c=c;
		}
		cnp=0,fadis[1]=0;
		Get_Gen_Info(1,0,0);
		Get_Pos(1,1);
		build(1,1,n);
		for (int i=1;i<n;i++)
			if (depth[e[i].a]>depth[e[i].b])
				swap(e[i].a,e[i].b);
		char str[10];
		int a,b;
		while (scanf("%s",str)&&str[0]!='D'){
			scanf("%d%d",&a,&b);
			if (str[0]=='C')
				change(1,1,n,p[e[a].b],b);
			else if (str[0]=='N')
				fupdate(a,b);
			else
				printf("%d\n",find(a,b));
		}
	}
	return 0;
}

  

posted @ 2017-12-03 21:35  zzd233  阅读(356)  评论(0编辑  收藏  举报