SPOJ 375 Query on a tree(树链剖分)

https://vjudge.net/problem/SPOJ-QTREE

题意:

给出一棵树,树上的每一条边都有权值,现在有查询和更改操作,如果是查询,则要输出u和v之间的最大权值。

思路:

树链剖分的模板题。

树链剖分简单来说,就是把树分成多条链,然后再将这些链映射到数据结构上处理(线段树,树状数组等等)。

具体的话可以看看这个http://blog.sina.com.cn/s/blog_6974c8b20100zc61.html

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #include<stack>
  7 #include<queue>
  8 #include<cmath>
  9 #include<map>
 10 #include<set>
 11 using namespace std;
 12 typedef long long ll;
 13 const int INF = 0x3f3f3f3f;
 14 const int maxn=20000+5;
 15 
 16 int n;
 17 int tot;
 18 int pos;
 19 int head[maxn];
 20 int dep[maxn];  //节点在树上的深度
 21 int top[maxn];  //节点所在重链的顶端节点
 22 int num[maxn];  //节点的子节点数
 23 int fa[maxn];   //父亲结点
 24 int p[maxn];    //节点与其父亲结点在线段树中的位置
 25 int fp[maxn];   //和p数组相反
 26 int son[maxn];  //节点的重儿子
 27 int e[maxn][3];
 28 
 29 struct node
 30 {
 31     int v,next;
 32 }edge[2*maxn];
 33 
 34 void addEdge(int u, int v)
 35 {
 36     edge[tot].v=v;
 37     edge[tot].next=head[u];
 38     head[u]=tot++;
 39 }
 40 
 41 
 42 //求出重儿子等等
 43 void dfs(int u, int pre, int d)
 44 {
 45     dep[u]=d;
 46     son[u]=-1;
 47     num[u]=1;
 48     fa[u]=pre;
 49     for(int i=head[u];i!=-1;i=edge[i].next)
 50     {
 51         int v=edge[i].v;
 52         if(v==pre)  continue;
 53         dfs(v,u,d+1);
 54         num[u]+=num[v];
 55         if(son[u]==-1 || num[son[u]]<num[v])  //找到子节点最多的作为重儿子
 56             son[u]=v;
 57     }
 58 }
 59 
 60 //处理top值以及在线段树上的位置
 61 void getpos(int u, int sp)
 62 {
 63     top[u]=sp;
 64     if(son[u]!=-1)  //先处理重儿子
 65     {
 66         p[u]=pos++;  //保证了一条链上的顶点在线段树上连续
 67         fp[p[u]]=u;
 68         getpos(son[u],sp);
 69     }
 70     else  //到了叶子节点就不再往下处理
 71     {
 72         p[u]=pos++;
 73         fp[p[u]]=u;
 74         return;
 75     }
 76     for(int i=head[u];i!=-1;i=edge[i].next) //处理其他顶点
 77     {
 78         int v=edge[i].v;
 79         if(v==son[u] || v==fa[u])  continue;
 80         getpos(v,v);
 81     }
 82 }
 83 
 84 int val[maxn<<2];
 85 int MAX[maxn<<2];
 86 
 87 
 88 void PushUp(int o)
 89 {
 90     MAX[o]=max(MAX[o<<1],MAX[o<<1|1]);
 91 }
 92 
 93 void build(int l, int r, int o)
 94 {
 95     if(l==r)
 96     {
 97         MAX[o]=val[l];
 98         return;
 99     }
100     int mid=(l+r)>>1;
101     build(l,mid,o<<1);
102     build(mid+1,r,o<<1|1);
103     PushUp(o);
104 }
105 
106 void update(int pos, int x, int l, int r, int o)
107 {
108     if(l==r)  {MAX[o]=x;return;}
109     int mid=(l+r)>>1;
110     if(pos<=mid)  update(pos,x,l,mid,o<<1);
111     else     update(pos,x,mid+1,r,o<<1|1);
112     PushUp(o);
113 }
114 
115 int query(int ql, int qr, int l, int r, int o)
116 {
117     if(ql<=l && qr>= r)  return MAX[o];
118     int mid=(l+r)>>1;
119     int res=0;
120     if(ql<=mid)  res=max(res,query(ql,qr,l,mid,o<<1));
121     if(qr>mid)   res=max(res,query(ql,qr,mid+1,r,o<<1|1));
122     return res;
123 }
124 
125 
126 int lca(int x, int y)
127 {
128     int ans=0;
129     while(top[x]!=top[y])  //不在一条链上时
130     {
131         if(dep[top[x]]<dep[top[y]])  swap(x,y);  //从深度较深的开始
132         ans=max(ans,query(p[top[x]],p[x],1,n,1));
133         x=fa[top[x]];  //x所在链的顶点的父节点,转到另一条链上
134     }
135     if(dep[x]>dep[y])  swap(x,y);
136     if(x!=y)  ans=max(ans,query(p[son[x]],p[y],1,n,1));
137     return ans;
138 }
139 
140 
141 int main()
142 {
143     //freopen("in.txt","r",stdin);
144     int T;
145     scanf("%d",&T);
146     while(T--)
147     {
148         tot=0;
149         memset(head,-1,sizeof(head));
150         scanf("%d",&n);
151         for(int i=1;i<n;i++)
152         {
153             scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
154             addEdge(e[i][0],e[i][1]);
155             addEdge(e[i][1],e[i][0]);
156         }
157         dfs(1,0,0);
158         pos=1;
159         getpos(1,1);
160         for(int i=1;i<n;i++)
161         {
162             if(dep[e[i][0]]<dep[e[i][1]]) swap(e[i][0],e[i][1]);
163             val[p[e[i][0]]]=e[i][2];
164         }
165         build(1,n,1);
166         char s[10]; int u,v;
167         while(scanf("%s",s))
168         {
169             if(s[0]=='D') break;
170             scanf("%d%d",&u,&v);
171             if(s[0]=='Q')  printf("%d
",lca(u,v));
172             else  update(p[e[u][0]],v,1,n,1);
173         }
174     }
175     return 0;
176 }
原文地址:https://www.cnblogs.com/zyb993963526/p/7427598.html