[ SPOJ 375 ] Query on a tree
阿新 • • 發佈:2018-11-04
truct 執行 code max else set query 操作 修改
\(\\\)
Description
給定 \(n\) 個點的樹,邊按輸入順序編號為\(1,2,...n-1\) 。
現要求按順序執行以下操作(共 \(m\) 次):
\(CHANGE\ i\ t_i\) 將第 \(i\) 條邊權值改為 \(t_i\)
\(QUERY\ a\ b\) 詢問從 \(a\) 點到 \(b\) 點路徑上的最大邊權
有多組測試數據,每組數據以 \(DONE\) 結尾
- \(n,m\le 10^5\)
\(\\\)
Solution
重鏈剖分,線段樹維護。
把邊權記錄在深度較深的葉節點上,具體編號的處理可以利用鄰接表存圖的方式。
修改就直接找到對應節點時間戳改了就好。
查詢找 \(Lca\) 的時候註意不要算上 \(Lca\) 的答案,因為那裏記錄的是 \(Lca\) 到其父節點的邊權。
Updata 的時候把 dfn 手殘寫成 pos 調了一天
\(\\\)
Code
#include<cmath> #include<cstdio> #include<cctype> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 100010 #define gc getchar #define Rg register #define mid ((l+r)>>1) #define inf 2000000000 using namespace std; inline int rd(){ int x=0; bool f=0; char c=gc(); while(!isdigit(c)){if(c=='-')f=1;c=gc();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();} return f?-x:x; } int n,m,tot,hd[N],bl[N],val[N]; struct edge{int to,nxt,w;}e[N<<1]; inline void add(int u,int v,int w){ e[++tot].to=v; e[tot].w=w; e[tot].nxt=hd[u]; hd[u]=tot; } int sz[N],f[N],d[N],son[N]; void dfs1(int u,int fa){ sz[u]=1; son[u]=0; for(Rg int i=hd[u],v;i;i=e[i].nxt) if((v=e[i].to)!=fa){ d[v]=d[u]+1; dfs1(v,u); val[v]=e[i].w; bl[(i+1)/2]=v; sz[u]+=sz[v]; f[v]=u; if(sz[v]>sz[son[u]]) son[u]=v; } } int cnt,dfn[N],top[N],pos[N]; void dfs2(int u,int fa){ dfn[u]=++cnt; pos[cnt]=u; if(!top[u]) top[u]=u; if(son[u]) top[son[u]]=top[u],dfs2(son[u],u); for(Rg int i=hd[u],v;i;i=e[i].nxt) if((v=e[i].to)!=fa&&v!=son[u]) dfs2(v,u); } struct segment{ int root,ptr; inline int newnode(){return ++ptr;} struct node{int ls,rs,mx;}c[N<<1]; inline void pushup(int rt){ c[rt].mx=max(c[c[rt].ls].mx,c[c[rt].rs].mx); } void build(int &rt,int l,int r){ rt=newnode(); if(l==r){ c[rt].mx=val[pos[l]]; return; } build(c[rt].ls,l,mid); build(c[rt].rs,mid+1,r); pushup(rt); } void updata(int rt,int l,int r,int p,int x){ if(l==r){c[rt].mx=x;return;} if(p<=mid) updata(c[rt].ls,l,mid,p,x); else updata(c[rt].rs,mid+1,r,p,x); pushup(rt); } int query(int rt,int l,int r,int L,int R){ if(l>R||r<L) return 0; if(l>=L&&r<=R) return c[rt].mx; int res=-inf; if(L<=mid) res=max(res,query(c[rt].ls,l,mid,L,R)); if(R>mid) res=max(res,query(c[rt].rs,mid+1,r,L,R)); return res; } }tree; inline int lca(int u,int v){ if(u==v) return 0; int res=-inf; while(top[u]!=top[v]){ if(d[top[u]]>d[top[v]]) u^=v^=u^=v; res=max(res,tree.query(tree.root,1,n,dfn[top[v]],dfn[v])); v=f[top[v]]; } if(d[u]>d[v]) u^=v^=u^=v; res=max(res,tree.query(tree.root,1,n,dfn[u]+1,dfn[v])); return res; } void work(){ n=rd(); cnt=tot=0; memset(f,0,sizeof(f)); memset(hd,0,sizeof(hd)); memset(top,0,sizeof(top)); memset(val,0,sizeof(val)); for(Rg int i=1,u,v,w;i<n;++i){ u=rd(); v=rd(); w=rd(); add(u,v,w); add(v,u,w); } dfs1(1,0); dfs2(1,0); tree.build(tree.root,1,n); char c; int x,y; while(1){ c=gc(); while(!isalpha(c)) c=gc(); if(c=='D') return; if(c=='Q'){x=rd();y=rd();printf("%d\n",lca(x,y));} else{x=rd();y=rd();tree.updata(tree.root,1,n,dfn[bl[x]],y);} } } int main(){ int t=rd(); while(t--) work(); return 0; }
[ SPOJ 375 ] Query on a tree