SPOJ VJudge QTREE - Query on a tree
Time Limit: 851MS | Memory Limit: 1572864KB | 64bit IO Format: %lld & %llu |
Description
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:
- CHANGE i ti : change the cost of the i-th edge to ti
or - QUERY a b : ask for the maximum edge cost on the path from node a to node b
Input
The first line of input contains an integer t, the number of test cases (t <= 20). t test cases follow.
For each test case:
- In the first line there is an integer N (N <= 10000),
- In the next N-1 lines, the i-th line describes the i-th edge: a line with three integers a b c denotes an edge between a, b of cost c (c <= 1000000),
- The next lines contain instructions "CHANGE i ti" or "QUERY a b",
- The end of each test case is signified by the string "DONE".
There is one blank line between successive tests.
Output
For each "QUERY" operation, write one integer representing its result.
Example
Input:
1
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE
Output:
1
3
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 using namespace std;
5 struct edge{
6 int u,v,w,next;
7 }e[20010];
8 struct node{
9 int l,r,val;
10 node *lc,*rc;
11 }*root=NULL;
12 int t,n,m,head[10010],js,p;
13 int fa[10010],son[10010],dep[10010],top[10010],pos[10010],siz[10010];
14 // fa存他的父亲 son存他的重孩子 dep它的深度 top他所在重链的链顶
15 //pos在线段树中的位置 siz[v]以v为顶的子树的孩子数
16 void memsett()
17 {
18 js=0;p=0;
19 memset(head,0,sizeof(head));
20 memset(e,0,sizeof(e));
21 memset(son,0,sizeof(son));
22 }
23 void add_edge(int u,int v,int w)
24 {
25 e[++js].u=u;e[js].v=v;e[js].w=w;
26 e[js].next=head[u];head[u]=js;
27 }
28 void dfs(int u,int f,int d)
29 {
30 fa[u]=f;dep[u]=d;siz[u]=1;
31 for(int i=head[u];i;i=e[i].next)
32 {
33 int v=e[i].v;
34 if(v!=f)
35 {
36 dfs(v,u,d+1);
37 siz[u]+=siz[v];
38 if(!son[u]||siz[son[u]]<siz[v])
39 son[u]=v;
40 }
41 }
42 }
43 void gettop(int u,int tp)
44 {
45 top[u]=tp;pos[u]=++p;
46 if(!son[u]) return;
47 gettop(son[u],tp);
48 for(int i=head[u];i;i=e[i].next)
49 {
50 int v=e[i].v;
51 if(v!=son[u]&&v!=fa[u])
52 gettop(v,v);
53 }
54 }
55 void build(node * &pt,int l,int r)
56 {
57 pt=new(node);
58 pt->l=l;pt->r=r;pt->val=0;
59 if(l==r)
60 {
61 pt->lc=pt->rc=NULL;
62 return ;
63 }
64 int mid=(l+r)/2;
65 build(pt->lc,l,mid);
66 build(pt->rc,mid+1,r);
67 }
68 void update(node * p,int ps,int val)
69 {
70 if(p->l==p->r)
71 {
72 p->val=val;return;
73 }
74 int mid=(p->l+p->r)/2;
75 if(ps<=mid) update(p->lc,ps,val);
76 else update(p->rc,ps,val);
77 p->val=max(p->lc->val,p->rc->val);
78 }
79 int query(node * p,int l,int r)
80 {
81 if(l<=p->l&&p->r<=r)return p->val;
82 int mid=(p->l+p->r)/2;
83 int ans=0;
84 if(l<=mid)ans=max(ans,query(p->lc,l,r));
85 if(r>mid)ans=max(ans,query(p->rc,l,r));
86 return ans;
87 }
88 int find(int u,int v)
89 {
90 int tp1=top[u],tp2=top[v],ans=0;
91 while(tp1!=tp2)
92 {
93 if(dep[tp1]<dep[tp2])
94 {
95 swap(tp1,tp2);swap(u,v);
96 }
97 ans=max(ans,query(root,pos[tp1],pos[u]));
98 u=fa[tp1];tp1=top[u];
99 }
100 if(u==v) return ans;
101 if(dep[u]>dep[v]) swap(u,v);
102 return max(ans,query(root,pos[u]+1,pos[v]));
103 }
104 int main()
105 {
106 scanf("%d",&t);
107 while(t--)
108 {
109 memsett();
110 scanf("%d",&n);
111 for(int i=1;i<=n-1;i++)
112 {
113 int x,y,z;
114 scanf("%d%d%d",&x,&y,&z);
115 add_edge(x,y,z);add_edge(y,x,z);
116 }
117 dfs(1,0,1);
118 gettop(1,1);
119 build(root,1,p);
120 for(int i=1;i<2*n-2;i+=2)// 建边表时见了两遍
121 {
122 if(dep[e[i].v]<dep[e[i].u]) swap(e[i].v,e[i].u);// 让v在下面
123 update(root,pos[e[i].v],e[i].w);
124 }
125 char s[15];int u,v;
126 while(scanf("%s",s)==1)
127 {
128 if(s[0]=='D') break;
129 scanf("%d%d",&u,&v);
130 if(s[0]=='Q') printf("%d\n",find(u,v));// 查询从u到v所经过的最大边权
131 else update(root,pos[e[u*2-1].v],v);// 将第u条边的权值修改为v
132 }
133 }
134 return 0;
135 }
思路:树链剖分基础题