spoj QTREE - Query on a tree(树链剖分+线段树单点更新,区间查询)

传送门:Problem QTREE

https://www.cnblogs.com/violet-acmer/p/9711441.html

 

题意:

    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 perform some instructions of the following form:
    有两个操作
    CHANGE i ti : change the cost of the i-th edge to ti(第i条边的权值变为ti)
    or
    QUERY a b : ask for the maximum edge cost on the path from node a to node b
    (查询节点a,b间路径的最大权值)

题解:

  树链剖分模板题,看代码理解的更快;

AC代码献上:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 using namespace std;
  6 #define ls(x) ((x)<<1)
  7 #define rs(x) ((x)<<1 | 1)
  8 const int maxn=10010;
  9 
 10 //===========链式前向星===============
 11 struct Node1
 12 {
 13     int to;
 14     int next;
 15 }edge[2*maxn];
 16 int head[maxn];
 17 int cnt;
 18 void addEdge(int u,int v)
 19 {
 20     edge[cnt].to=v;
 21     edge[cnt].next=head[u];
 22     head[u]=cnt++;
 23 }
 24 //====================================
 25 //=========树链剖分用到的变量=========
 26 int fa[maxn];//fa[u] : 节点u的父节点
 27 int newId[maxn];//newId[u] : u与其父亲节点的连边在线段树中的位置
 28 int depth[maxn];//depth[u] : 节点u的深度
 29 int siz[maxn];//siz[u] : 以u为根的子树的节点数
 30 int top[maxn];//top[u] : 节点u所在的重链的顶端节点
 31 int son[maxn];//son[u] : 节点u重儿子
 32 int label;//记录newId[]中新边对应的编号
 33 //====================================
 34 //==========两次DFS()================
 35 void dfs1(int u,int f,int d) //第一遍dfs求出fa[],depth[],siz[],son[]
 36 {
 37     depth[u]=d;
 38     fa[u]=f;
 39     siz[u]=1;
 40     for(int i=head[u];~i;i=edge[i].next)
 41     {
 42         int to=edge[i].to;
 43         if(to != f)
 44         {
 45             dfs1(to,u,d+1);
 46             siz[u] += siz[to];
 47             if(son[u] == -1 || siz[to] > siz[son[u]])
 48                 son[u] = to;
 49         }
 50     }
 51 }
 52 void dfs2(int u,int sp) //第二遍dfs求出top[]和newId[]
 53 {
 54     top[u]=sp;
 55     newId[u]=++label;
 56     if(son[u] == -1)
 57         return ;
 58     dfs2(son[u],sp);
 59 
 60     for(int i=head[u];~i;i=edge[i].next)
 61     {
 62         int to=edge[i].to;
 63         if(to != son[u] && to != fa[u])
 64             dfs2(to,to);
 65     }
 66 }
 67 //===================================
 68 //=============线段树================
 69 struct Node2
 70 {
 71     int l,r;
 72     int Max;
 73     int mid()
 74     {
 75         return l+((r-l)>>1);
 76     }
 77 }segTree[maxn*4];
 78 void buildTree(int l,int r,int pos)
 79 {
 80     segTree[pos].l = l,segTree[pos].r = r;
 81     segTree[pos].Max = 0;
 82     if(l == r)
 83         return;
 84 
 85     int mid = (l+r)/2;
 86     buildTree(l,mid,ls(pos));
 87     buildTree(mid+1,r,rs(pos));
 88 }
 89 void push_up(int k)//向上更新
 90 {
 91     segTree[k].Max = max(segTree[ls(k)].Max,segTree[rs(k)].Max);
 92 }
 93 void update(int k,int val,int pos) //单点更新
 94 {
 95     if(segTree[pos].l == segTree[pos].r)
 96     {
 97         segTree[pos].Max = val;
 98         return;
 99     }
100 
101     int mid=segTree[pos].mid();
102 
103     if(k <= mid)
104         update(k,val,ls(pos));
105     else
106         update(k,val,rs(pos));
107     push_up(pos);
108 }
109 int query(int l,int r,int pos)//查询线段树中[l,r]的最大值
110 {
111     if(segTree[pos].l == l && segTree[pos].r == r)
112         return segTree[pos].Max;
113 
114     int mid=segTree[pos].mid();
115 
116     if(r <= mid)
117         return query(l,r,ls(pos));
118     else if(l > mid)
119         return query(l,r,rs(pos));
120     else
121         return max(query(l,mid,ls(pos)),query(mid+1,r,rs(pos)));
122 }
123 int Find(int u,int v)//查询u->v边的最大值
124 {
125     int res=0;
126     while(top[u] != top[v])
127     {
128         if(depth[top[u]] > depth[top[v]])
129         {
130             res=max(res,query(newId[top[u]],newId[u],1));
131             u=fa[top[u]];
132         }
133         else
134         {
135             res=max(res,query(newId[top[v]],newId[v],1));
136             v=fa[top[v]];
137         }
138     }
139     if(u == v)
140         return res;
141     if(depth[u] > depth[v])
142         swap(u,v);
143     return max(res,query(newId[son[u]],newId[v],1));
144 }
145 //===================================
146 void Init()
147 {
148     cnt=0;
149     memset(head,-1,sizeof(head));
150     label=0;
151     memset(son,-1,sizeof(son));
152 }
153 int e[maxn][3];
154 int main()
155 {
156     int T;
157     scanf("%d",&T);
158     while(T--)
159     {
160         int n;
161         Init();
162         scanf("%d",&n);
163         for(int i=1;i < n;++i)
164         {
165             scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
166             addEdge(e[i][0],e[i][1]);
167             addEdge(e[i][1],e[i][0]);
168         }
169         dfs1(1,0,0);
170         dfs2(1,1);
171         buildTree(1,label,1);
172         for(int i=1;i < n;++i)
173         {
174             if(depth[e[i][0]] > depth[e[i][1]])
175                 swap(e[i][0],e[i][1]);//确保 e[i][0] 为 e[i][1]的父节点
176             update(newId[e[i][1]],e[i][2],1);//更新e[i][1]与其父节点e[i][0]的连边在线段树中的位置
177         }
178         char op[10];
179         while(scanf("%s",op) && op[0] != 'D')
180         {
181             int u,v;
182             scanf("%d%d",&u,&v);
183             if(op[0] == 'Q')
184                 printf("%d\n",Find(u,v));
185             else
186                 update(newId[e[u][1]],v,1);
187         }
188     }
189 }
View Code

 


分割线:2019.5.10

省赛倒计时2天;

熟悉一下树链剖分,改改代码风格:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define ls(x) (x<<1)
  4 #define rs(x) (x<<1|1)
  5 #define mem(a,b) memset(a,b,sizeof(a))
  6 const int maxn=1e4+50;
  7 
  8 int n;///n个节点
  9 int e[maxn][3];///节点e[i][0]与节点e[i][1]有条权值为e[i][2]的边
 10 int num;
 11 int head[maxn];
 12 struct Edge
 13 {
 14     int to;
 15     int next;
 16 }G[maxn<<1];
 17 void addEdge(int u,int v)
 18 {
 19     G[num]=Edge{v,head[u]};
 20     head[u]=num++;
 21 }
 22 int fa[maxn];///fa[u]:节点u的父节点
 23 int tid[maxn];///tid[u]:节点u在线段树中的新编号
 24 int rid[maxn];///tid[u]=cnt,rid[cnt]=u,通过线段树中的编号查找节点
 25 int dep[maxn];///节点的深度
 26 int siz[maxn];///siz[u]:以u为根的子树的节点数
 27 int son[maxn];///son[u]:节点u重儿子
 28 int top[maxn];///top[u]:节点u所在重链的顶端节点
 29 struct Seg
 30 {
 31     int l,r;
 32     int maxVal;///区间维护最大值,根据题意而定
 33     int mid(){return l+((r-l)>>1);}
 34     int len(){return r-l+1;}
 35 }seg[maxn<<2];
 36 void pushUp(int pos)
 37 {
 38     seg[pos].maxVal=max(seg[ls(pos)].maxVal,seg[rs(pos)].maxVal);
 39 }
 40 void buildSegTree(int l,int r,int pos)
 41 {
 42     seg[pos].l=l;
 43     seg[pos].r=r;
 44     seg[pos].maxVal=0;
 45     if(l == r)
 46         return ;
 47     int mid=l+((r-l)>>1);
 48     buildSegTree(l,mid,ls(pos));
 49     buildSegTree(mid+1,r,rs(pos));
 50 }
 51 void Update(int l,int val,int pos)///单点更新
 52 {
 53     if(seg[pos].l == seg[pos].r)
 54     {
 55         seg[pos].maxVal=val;
 56         return ;
 57     }
 58     int mid=seg[pos].mid();
 59     if(l <= mid)
 60         Update(l,val,ls(pos));
 61     else
 62         Update(l,val,rs(pos));
 63     pushUp(pos);
 64 }
 65 int Query(int l,int r,int pos)///区间查询
 66 {
 67     if(seg[pos].l == l && seg[pos].r == r)
 68         return seg[pos].maxVal;
 69     int mid=seg[pos].mid();
 70     if(r <= mid)
 71         return Query(l,r,ls(pos));
 72     else if(l > mid)
 73         return Query(l,r,rs(pos));
 74     else
 75         return max(Query(l,mid,ls(pos)),Query(mid+1,r,rs(pos)));
 76 }
 77 int Find(int u,int v)
 78 {
 79     int topU=top[u];
 80     int topV=top[v];
 81     int ans=0;
 82     while(topU != topV)///u,v不在一条重链上
 83     {
 84         if(dep[topU] > dep[topV])///人为规定topU的深度低
 85         {
 86             swap(topU,topV);
 87             swap(u,v);
 88         }
 89         ans=max(ans,Query(tid[topV],tid[v],1));
 90         v=fa[topV];///v来到topV的父节点所在的重链
 91         topV=top[v];
 92     }
 93     if(u == v)
 94         return ans;
 95 
 96     if(dep[u] > dep[v])
 97         swap(u,v);
 98     return max(ans,Query(tid[son[u]],tid[v],1));
 99 }
100 void DFS1(int u,int f,int depth)///第一遍DFS求出fa,dep,siz,son
101 {
102     fa[u]=f;
103     siz[u]=1;
104     dep[u]=depth;
105     for(int i=head[u];~i;i=G[i].next)
106     {
107         int v=G[i].to;
108         if(v == f)///此处是v == f才continue,在这儿出过错
109             continue;
110         DFS1(v,u,depth+1);
111         siz[u] += siz[v];
112         if(son[u] == -1 || siz[v] > siz[son[u]])///更新重儿子
113             son[u]=v;
114     }
115 }
116 void DFS2(int u,int anc,int &k)///第二遍DFS求出tid,rid,top
117 {
118     top[u]=anc;
119     tid[u]=++k;
120     rid[k]=u;
121     if(son[u] == -1)
122         return ;
123     DFS2(son[u],anc,k);
124 
125     for(int i=head[u];~i;i=G[i].next)
126     {
127         int v=G[i].to;
128         if(v != son[u] && v != fa[u])
129             DFS2(v,v,k);
130     }
131 }
132 void Solve()
133 {
134     DFS1(1,0,0);
135     int k=0;
136     DFS2(1,1,k);
137     buildSegTree(1,k,1);///[1,k]重新编号的节点建树
138 
139     for(int i=1;i < n;++i)
140     {
141         ///将e[i][0]与e[i][1]的边权存入儿子节点e[i][1]中
142         if(dep[e[i][0]] > dep[e[i][1]])
143             swap(e[i][0],e[i][1]);
144         ///更新e[i][1]与其父节点e[i][0]的连边在线段树中的位置
145         Update(tid[e[i][1]],e[i][2],1);
146     }
147     char order[10];
148     while(~scanf("%s",order) && order[0] != 'D')
149     {
150         int u,v;
151         scanf("%d%d",&u,&v);
152         if(order[0] == 'Q')
153             printf("%d\n",Find(u,v));///查询节点u,v间路径的最大值
154         else///更新第u条边的权值,变为v,第u条边的权值信息记录在了tid[e[u][1]]中
155             Update(tid[e[u][1]],v,1);
156     }
157 }
158 
159 void Init()///初始化head,num,son
160 {
161     num=0;
162     mem(head,-1);
163     mem(son,-1);
164 }
165 int main()
166 {
167     int test;
168     while(~scanf("%d",&test))
169     {
170         while(test--)
171         {
172             Init();///多组输入test,Init()放在while(test--)内
173             scanf("%d",&n);
174             for(int i=1;i < n;++i)///n-1条边
175             {
176                 int u,v,w;
177                 scanf("%d%d%d",&u,&v,&w);
178                 e[i][0]=u;
179                 e[i][1]=v;
180                 e[i][2]=w;
181                 addEdge(u,v);
182                 addEdge(v,u);
183             }
184             Solve();
185         }
186     }
187     return 0;
188 }
View Code

 

posted @ 2018-09-27 09:40  HHHyacinth  阅读(367)  评论(0编辑  收藏  举报