375. Query on a treeProblem 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:
The first line of input contains an integer t, the number of test cases (t <= 20). t test cases follow.
For each test case:
There is one blank line between successive tests.
For each "QUERY" operation, write one integer representing its result.
Input: 1 3 1 2 1 2 3 2 QUERY 1 2 CHANGE 1 3 QUERY 1 2 DONE Output: 1 3
题意:
给你一颗树。然后你可以对这个树就行两种操作。
1.修改某条边的边权。
2.查询u->v路径上。最大的边权。
题目链接点击打开链接
思路:
没学树链剖分前,觉得这个算法比较难,学了下发现没有想象的那么难。
讲解见点击打开链接还是蛮浅显易懂的。
#include<algorithm> #include<iostream> #include<string.h> #include<stdio.h> using namespace std; const int INF=0x3f3f3f3f; const int maxn=10010; typedef long long ll; #define lson L,mid,ls #define rson mid+1,R,rs int fa[maxn],dep[maxn],sz[maxn],son[maxn], id[maxn],top[maxn],cnt,ptr; //记sz[u]表示以u为根的子树的节点数,dep[u]表示u的深度(根深度为1),top[u]表示u所在的重链的顶端节点, //fa[u]表示u的父亲,son[u]表示与u在同一重链上的u的儿子节点(姑且称为重儿子),id[u]表示u与其父亲节点的连边(姑且称为u的父边)在线段树中的位置。 struct node { int v; node *next; } ed[maxn<<1],*head[maxn]; int mav[maxn<<2],uu[maxn],vv[maxn],wei[maxn]; void build(int L,int R,int rt) { mav[rt]=-INF; if(L==R) return; int ls=rt<<1,rs=ls|1,mid=(L+R)>>1; build(lson); build(rson); } void update(int L,int R,int rt,int p,int d) { if(L==R) { mav[rt]=d; return; } int ls=rt<<1,rs=ls|1,mid=(L+R)>>1; if(p<=mid) update(lson,p,d); else update(rson,p,d); mav[rt]=max(mav[ls],mav[rs]); } int qu(int L,int R,int rt,int l,int r) { if(l<=L&&R<=r) return mav[rt]; int ls=rt<<1,rs=ls|1,mid=(L+R)>>1,tp=-INF; if(l<=mid) tp=max(tp,qu(lson,l,r)); if(r>mid) tp=max(tp,qu(rson,l,r)); return tp; } void adde(int u,int v) { ed[cnt].v=v; ed[cnt].next=head[u]; head[u]=&ed[cnt++]; } void dfs(int u) { int v,ms=-INF; sz[u]=1,son[u]=-1; for(node *p=head[u];p!=NULL;p=p->next) { v=p->v; if(v==fa[u]) continue; fa[v]=u; dep[v]=dep[u]+1; dfs(v); if(sz[v]>ms) ms=sz[v],son[u]=v; sz[u]+=sz[v]; } } void getid(int u,int ft) { id[u]=++ptr,top[u]=ft; if(son[u]!=-1) getid(son[u],top[u]); for(node *p=head[u];p!=NULL;p=p->next) { if(p->v==fa[u]||p->v==son[u]) continue; getid(p->v,p->v); } } void init(int rt) { fa[rt]=-1; dep[rt]=ptr=0; dfs(rt); getid(rt,rt);//根没有父边。但是在线段树中占了1的位置。但是不会用到。只是写起来方便 build(1,ptr,1);//1-ptr。ptr条边。是算上根的虚拟边的。 } inline int calc(int u,int v) { int f1=top[u],f2=top[v],tp=-INF; while(f1!=f2) { if(dep[f1]<dep[f2]) swap(f1,f2),swap(u,v); tp=max(tp,qu(1,ptr,1,id[f1],id[u])); u=fa[f1],f1=top[u];//开始把fa[f1]写成了fa[u]。T了一早上。。。哎。。。 } if(u==v) return tp; if(dep[u]>dep[v]) swap(u,v); tp=max(tp,qu(1,ptr,1,id[son[u]],id[v])); return tp; } int main() { int n,u,v,w,t,rt,i; char cmd[100]; scanf("%d",&t); while(t--) { scanf("%d",&n); rt=(n+1)/2; cnt=0; memset(head,0,sizeof head); for(i=1;i<n;i++) { scanf("%d%d%d",&u,&v,&w); uu[i]=u,vv[i]=v,wei[i]=w; adde(u,v); adde(v,u); } init(rt); for(i=1;i<n;i++) { if(dep[uu[i]]>dep[vv[i]]) swap(uu[i],vv[i]); update(1,ptr,1,id[vv[i]],wei[i]); } while(1) { scanf("%s",cmd); if(cmd[0]=='D') break; scanf("%d%d",&u,&v); if(cmd[0]=='C') update(1,ptr,1,id[vv[u]],v); else printf("%d\n",calc(u,v)); } } return 0; }
原文地址:http://blog.csdn.net/bossup/article/details/39317473