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 }
思路:树链剖分基础题
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步