1. 程式人生 > >[SPOJ - QTREE] Query on a tree

[SPOJ - QTREE] Query on a tree

單點 head 區間 targe while pan oid ans 一個

題目傳送門:[SPOJ - QTREE] Query on a tree

題目大意:

存在一個樹,樹上有n個節點和n-1條邊,對這棵樹進行以下兩種操作

CHANGE i ti :將樹的第i條邊的權值改為ti

QUERY a b :查詢a->b路徑中權值最大的邊的值

分析:

邊權樹鏈剖分裸題,CHANGE操作是更改第i條邊,因此邊用結構體數組將其保存,用邊

的兩個點中深度較大的點記錄邊的權值,更改時更改該點,為了方便操作,兩次dfs之後

重新遍歷保存邊的結構體數組,將深度較大的邊存在E[i].u中。更新時更新該點即可。

註意:因為用深度較大的點記錄該邊的權值,x點所記錄的權值是邊x->fa[x]的權值,因此在

對x->y路徑進行操作時,其實是對son[x]->y的點所記錄的權值進行操作.

線段樹維護區間最大值,查詢為區間查詢

代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1 
const int MAX=10000;
const int INF=1<<29;
int head[MAX],cnt;
int fa[MAX],deep[MAX],son[MAX],size[MAX],top[MAX],id[MAX],rk[MAX],tot; int t,n,x,y,a[MAX]; int tree[MAX<<2]; char op[10]; struct Edge{ int next,to; }edge[MAX*2]; void add(int u,int v) { edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt++; } struct E{ //
記錄邊信息 int u,v,w; }e[MAX]; void dfs1(int u,int f,int d) { fa[u]=f; deep[u]=d; size[u]=1; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(v!=fa[u]) { dfs1(v,u,d+1); size[u]+=size[v]; if(son[u]==-1||size[v]>size[son[u]]) son[u]=v; } } } void dfstop(int u,int t) { top[u]=t; id[u]=tot++; rk[id[u]]=u; if(son[u]==-1)return; dfstop(son[u],t); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(v!=son[u]&&v!=fa[u]) dfstop(v,v); } } void PushUp(int rt) //維護區間最大值 { tree[rt]=max(tree[rt<<1],tree[rt<<1|1]); } void Build(int l,int r,int rt) { if(l==r) { tree[rt]=a[rk[l]]; return; } int m=l+r>>1; Build(ls),Build(rs); PushUp(rt); } void Update(int pos,int val,int l,int r,int rt)//單點更新 { if(l==r) { tree[rt]=val; return; } int m=l+r>>1; if(pos<=m)Update(pos,val,ls); else Update(pos,val,rs); PushUp(rt); } int Query(int L,int R,int l,int r,int rt)//區間查詢 { if(L<=l&&r<=R) return tree[rt]; int ans=-INF; int m=l+r>>1; if(L<=m)ans=max(ans,Query(L,R,ls)); if(R>m)ans=max(ans,Query(L,R,rs)); return ans; } int solve(int x,int y)//查詢x->y路徑中邊權最大的值 { int ans=-INF; while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]]) swap(x,y); ans=max(ans,Query(id[top[x]],id[x],1,tot,1)); x=fa[top[x]]; } if(deep[x]>deep[y]) swap(x,y); ans=max(ans,Query(id[son[x]],id[y],1,tot,1));//x->y路徑的權值記錄在son[x]->y之間,x點記錄的是x到其父親節點的權值 return ans; } void init() { memset(head,-1,sizeof(head));cnt=0; memset(son,-1,sizeof(son));tot=1; memset(tree,0,sizeof(tree)); memset(a,0,sizeof(a)); } int main() { scanf("%d",&t); while(t--) { init(); scanf("%d",&n); for(int i=1;i<n;i++) { scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); add(e[i].u,e[i].v),add(e[i].v,e[i].u); } dfs1(1,-1,0),dfstop(1,1); for(int i=1;i<n;i++) { if(deep[e[i].u]<deep[e[i].v]) //將邊兩邊的點深度較大的點記錄在u中 swap(e[i].u,e[i].v); a[e[i].u]=e[i].w; //深度較大的點保存該邊的權值 } Build(1,tot,1); while(scanf("%s",op)) { if(op[0]==D)break; if(op[0]==C) { scanf("%d%d",&x,&y); Update(id[e[x].u],y,1,tot,1); //更新深度較大的點的權值即更新該邊的權值 } if(op[0]==Q) { scanf("%d%d",&x,&y); printf("%d\n",solve(x,y)); } } } return 0; }

[SPOJ - QTREE] Query on a tree