题意:给出一个n个节点的树,边的标号分别是1-n-1,然后有两种操作,CHANGE 将第i条边的权值改成ti,QUERY 查询a点到b点中的边的最大权值。。
QTREE系列的第一题,第一次写树链剖分,树链剖分之后用线段树解决,中途出现了RE和WA,找了几天才解决,都在代码中注释了。。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<limits.h>
#define ls (k<<1)
#define rs (k<<1|1)
using namespace std;
const int MAXN=10010;
const int INF=INT_MAX;
struct EDGE
{
int v,next;
}edge[MAXN<<1];
int head[MAXN],size;
int totw;
int fa[MAXN],dep[MAXN],siz[MAXN],son[MAXN],w[MAXN],top[MAXN];
void init() //初始化
{
memset(head,-1,sizeof(head));
memset(dep,0,sizeof(dep));
memset(siz,0,sizeof(siz));
memset(son,-1,sizeof(son));
memset(fa,-1,sizeof(fa));
memset(top,0,sizeof(top));
size=0;
totw=0;
}
void add_edge(int u,int v)
{
edge[size].v=v;
edge[size].next=head[u];
head[u]=size++;
}
void dfs1(int u,int f,int deep)
{
siz[u]=1; //自己算1
int mmax=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(v!=f)
{
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v,u,deep+1);
siz[u]+=siz[v];
if(siz[v]>mmax)//找出最大的子节点
{
mmax=siz[v];
son[u]=v; //重孩子
}
}
}
}
void dfs2(int u,int f) //f表示一条重链的顶端
{
top[u]=f; //重链上的点都指向最高的点
totw++;
w[u]=totw; //标号先标记重链上的边
//printf("2222\n");
if(son[u]!=-1)
dfs2(son[u],f); //沿重链深搜下去,保证先标号
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(v!=fa[u]&&v!=son[u])
dfs2(v,v); //轻链
}
}
struct TREE
{
int l,r;
int mmax;
int mid()
{
return (l+r)>>1;
}
}tree[MAXN<<2];
struct LINE
{
int x,y,c;
}l[MAXN];
int val[MAXN];
void pushup(int k)
{
tree[k].mmax=max(tree[ls].mmax,tree[rs].mmax);
}
void build(int l,int r,int k)
{
tree[k].l=l;
tree[k].r=r;
if(l==r)
{
tree[k].mmax=val[l];
return;
}
int mid=tree[k].mid();
build(l,mid,ls);
build(mid+1,r,rs);
pushup(k);
}
void update(int va,int pos,int k)
{
if(tree[k].l==tree[k].r)
{
tree[k].mmax=va;
return;
}
int mid=tree[k].mid();
if(pos<=mid)
update(va,pos,ls);
else
update(va,pos,rs);
pushup(k);
}
int query(int l,int r,int k)
{
if(tree[k].l>=l&&tree[k].r<=r)
{
return tree[k].mmax;
}
int mid=tree[k].mid();
if(r<=mid)
return query(l,r,ls);
else if(l>mid)
return query(l,r,rs);
else
{
int t1=query(l,mid,ls);
int t2=query(mid+1,r,rs);
return max(t1,t2);
}
}
void update1(int x,int y,int val)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) //这里应该是dep,不是top
swap(x,y);
update(val,w[x],1);
x=fa[top[x]];
}
if(x==y)
return;
if(dep[x]<dep[y])
swap(x,y);
update(val,w[x],1);
//printf("val=%d\n",val);
}
int query1(int x,int y)
{
int ans=-INF;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
ans=max(ans,query(w[top[x]],w[x],1));
//printf("ans=%d\n",ans);
x=fa[top[x]];
}
if(x==y)
return ans;
if(dep[x]>dep[y]) //写成top导致RE
swap(x,y);
return max(ans,query(w[x]+1,w[y],1));
}
char str[20];
int main()
{
int t,n,i;
//freopen("in.txt","r",stdin);
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
init();
int u,v,c;
for(i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&c);
l[i].x=u;
l[i].y=v;
l[i].c=c;
add_edge(u,v);
add_edge(v,u);
//printf("XXXX1\n");
}
totw=0;
dfs1(1,-1,0);
//printf("11111\n");
dfs2(1,1);
for(i=1;i<n;i++)
{
int a=l[i].x,b=l[i].y;
if(dep[a]<dep[b])
swap(a,b);
val[w[a]]=l[i].c;
//printf("XXXX2\n");
}
build(1,totw,1);
while(scanf("%s",str)!=EOF)
{
if(str[0]=='D')
break;
int x,y;
scanf("%d%d",&x,&y);
if(str[0]=='Q')
printf("%d\n",query1(x,y));
else
{
//printf("i=%d c=%d\n",i,l[i].c);
int a=l[x].x,b=l[x].y;
update1(a,b,y);
}
}
if(t)
printf("\n");
}
return 0;
}
/*
2
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 -100
QUERY 1 2
DONE
*/