SPOJ - QTREE Query on a tree题解

题目大意:

  一棵树,有边权,有两个操作:1.修改一条边的权值;2.询问两点间路径上的边的权值的最大值。

思路:

  十分裸的树链剖分+线段树,无非是边权要放到深度大的一端的点上,但是有两个坑爹的地方,改了好久:

  1.数组定义10000和40000会TLE,要乘10;

  2.以前的树剖求解的最后是这样的:

    if (deep[x]>deep[y]) swap(x,y);
    return max(ans,MAX(1,n,id[x],id[y],1));

  但是WA了,膜拜大神后发现这样就AC了:

    if (x==y) return ans;
    if (dep[x]>dep[y]) swap(x,y);
    return max(ans,ask(1,n,id[x]+1,id[y],1));

  以前应该是错了。

代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 const int M=100009;
 5 int n,cnt,t,p[M],hea[M],size[M],v[M],a[M],b[M],c[M],nex[M],dep[M],top[M],id[M],tree[M<<2];
 6 char s[M]; bool vis[M];
 7
 8 int read()
 9 {
10     int x=0; bool f=0; char ch=getchar();
11     while (ch<‘0‘ || ch>‘9‘) { if (ch==‘-‘) f=1; ch=getchar(); }
12     while (ch>=‘0‘ && ch<=‘9‘) x=(x<<1)+(x<<3)+ch-48,ch=getchar();
13     return f?-x:x;
14 }
15
16 void add(int x,int y) { v[++cnt]=y,nex[cnt]=hea[x],hea[x]=cnt; }
17
18 void dfs1(int x,int fa,int h)
19 {
20     size[x]=1,dep[x]=h,p[x]=fa;
21     for (int i=hea[x],y;i;i=nex[i])
22         if ((y=v[i])^fa) dfs1(y,x,h+1),size[x]+=size[y];
23 }
24
25 void dfs2(int x,int chain)
26 {
27     int i,k=0,y;
28     id[x]=++t,top[x]=chain;
29     for (i=hea[x];i;i=nex[i])
30         if (size[y=v[i]]>size[k] && y^p[x]) k=y;
31     if (!k) return; dfs2(k,chain);
32     for (i=hea[x];i;i=nex[i])
33         if ((y=v[i])^p[x] && k^y) dfs2(y,y);
34 }
35
36 void push_up(int k) { tree[k]=max(tree[k<<1],tree[k<<1|1]); }
37
38 void change(int L,int R,int x,int val,int cur)
39 {
40     if (L==R) { tree[cur]=val; return; }
41     int mid=L+R>>1;
42     if (x>mid) change(mid+1,R,x,val,cur<<1|1);
43     else change(L,mid,x,val,cur<<1);
44     push_up(cur);
45 }
46
47 int ask(int L,int R,int l,int r,int cur)
48 {
49     if (l<=L && R<=r) return tree[cur];
50     int mid=L+R>>1;
51     if (r<=mid) return ask(L,mid,l,r,cur<<1);
52     else if (l>mid) return ask(mid+1,R,l,r,cur<<1|1);
53          else return max(ask(L,mid,l,mid,cur<<1),ask(mid+1,R,mid+1,r,cur<<1|1));
54 }
55
56 int qry(int x,int y)
57 {
58     int ans=-10000000;
59     for (;top[x]^top[y];x=p[top[x]])
60     {
61         if (dep[top[x]]<dep[top[y]]) swap(x,y);
62         ans=max(ans,ask(1,n,id[top[x]],id[x],1));
63     }
64     if (x==y) return ans;
65     if (dep[x]>dep[y]) swap(x,y);
66     return max(ans,ask(1,n,id[x]+1,id[y],1));
67 }
68
69 int main()
70 {
71     for (int T=read(),i;T;--T)
72     {
73         n=read(),cnt=t=0;
74         for (i=0;i<=n;++i) hea[i]=0;
75         for (i=1;i<n;++i)
76         {
77             a[i]=read(),b[i]=read(),c[i]=read();
78             add(a[i],b[i]),add(b[i],a[i]);
79         }
80         dfs1(1,1,1),dfs2(1,1);
81         for (i=1;i<n;++i)
82         {
83             if (dep[a[i]]<dep[b[i]]) swap(a[i],b[i]);
84             change(1,n,id[a[i]],c[i],1);
85         }
86         for (;;)
87         {
88             scanf("%s",s);
89             if (s[0]==‘D‘) break;
90             int x=read(),y=read();
91             if (s[0]==‘C‘) change(1,n,id[a[x]],y,1);
92             if (s[0]==‘Q‘) printf("%d\n",qry(x,y));
93         }
94     }
95     return 0;
96 }
时间: 2024-10-16 14:26:56

SPOJ - QTREE Query on a tree题解的相关文章

SPOJ QTREE Query on a tree ——树链剖分 线段树

[题目分析] 垃圾vjudge又挂了. 树链剖分裸题. 垃圾spoj,交了好几次,基本没改动却过了. [代码](自带常数,是别人的2倍左右) #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 20005 int T,n,fr[maxn],h[maxn],to[maxn],ne[maxn]

SPOJ QTREE - Query on a tree

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 tior QUERY

SPOJ QTREE Query on a tree --树链剖分

题意:给一棵树,每次更新某条边或者查询u->v路径上的边权最大值. 解法:做过上一题,这题就没太大问题了,以终点的标号作为边的标号,因为dfs只能给点分配位置,而一棵树每条树边的终点只有一个. 询问的时候,在从u找到v的过程中顺便查询到此为止的最大值即可. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath&

spoj 375 query on a tree 题解

题目大意:维护一棵树,支持查询两点间路径最大值,以及修改某边的权值. 裸的树链剖分+线段树..不多说 这题卡常数卡的厉害啊!vector完全过不了 然后..我就写了我一点都不熟悉的普通邻接表. 虽然代码丑,虽然依然很慢,虽然有点长,但是它至少A了.. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 const int INF=~0U>&g

SPOJ QTREE Query on a Tree【树链剖分模板题】

树链剖分,线段树维护~ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> using namespace std; const int MAXN = 10014; struct Edge { int to,next; }edge[MAXN*2]; int head[MAXN],tot; int top[MA

QTREE - Query on a tree

QTREE - Query on a tree 题目链接:http://www.spoj.com/problems/QTREE/ 参考博客:http://blog.sina.com.cn/s/blog_7a1746820100wp67.html 树链剖分入门题 代码如下(附注解): 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define lson (x<<1) 5 #d

SP375 QTREE - Query on a tree (树剖)

题目 SP375 QTREE - Query on a tree 解析 也就是个蓝题,因为比较长 树剖裸题(基本上),单点修改,链上查询. 可以看到这个题然我们对边进行操作,我们的树剖是对节点进行操作的,所以我们考虑把边权转移到点权上. 发现我们节点的点权是连向它的边的边权,所以我们要修改或查询边权的话,我们修改或查询的实际上是其连向点的点权, 假设我们要修改1-4之间的这两条边 我们修改的实际上就是这两个点 所以我们链上修改或查询的时候,不要修改或查询深度较浅的节点. 然后这是SPOJ上的题,

spoj 375. Query on a tree 【树链剖分--插点问线 】

题目:spoj 375. Query on a tree 题意:题意很清晰,就是给你一颗树,每两点之间有权值,然后改变一些权值,问一条路径上的最大值. 分析:入门题目,直接套树链模板 AC代码: #include <cstdio> #include <algorithm> #include <iostream> #include <string.h> using namespace std; const int N = 10010; #define Del(

SP375 QTREE - Query on a tree

SP375 QTREE - Query on a tree 我是借这道题来说说如何从c++改到c的 1.我怕麻烦,所以把结构体拆了(忍痛割爱我封装的线段树) 2.max.swap函数进行了手写 max: ll llmax(ll x,ll y){return x>y?x:y;} swap: x^=y^=x^=y emm...这的确是一个神奇的swap,不用函数 至于为什么是对的用人类智慧法即可 c++代码:(线段树封装) #include<bits/stdc++.h> using name