wxwoo's blog

原题目链接

树上链最值查询

做法很多,LCT,树上倍增,树剖都可以

但由于LCT常数过大,树上倍增比树剖常数大,这里使用树链剖分

边权转点权是树剖常用套路,将边权转成深度较大的点的点权,查询时注意避开两点的LCA的权值

由于不带修改,树剖后用ST表维护,时间复杂度$\mathcal{O}(n\log n)$,比用线段树维护$\mathcal{O}(n\log ^2n)$还少一个log

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
template<typename T>inline void read(T &x)
{
char ch=getchar();
T f=1;
x=0;
while(!('0'<=ch&&ch<='9'))
{
if(ch=='-')
f=-1;
ch=getchar();
}
while('0'<=ch&&ch<='9')
{
x=(x<<3)+(x<<1)+ch-48;
ch=getchar();
}
x*=f;
}
const int N=100010,logN=20;
int n,m;
int head[N],nxt[N<<1],to[N<<1],w[N<<1],e;
int fa[N],son[N],dep[N],wt[N],sz[N],id[N],seq[N],top[N],cnt;
int st[N][logN][2],_log[N];
inline void add(int u,int v,int f)
{
to[++e]=v;
w[e]=f;
nxt[e]=head[u];
head[u]=e;
}
inline void build()
{
_log[0]=-1;
for(int i=1;i<=n;++i)
{
st[i][0][0]=st[i][0][1]=wt[seq[i]];
_log[i]=_log[i>>1]+1;
}
for(int j=1;j<=logN;++j)
{
for(int i=1;i+(1<<j)-1<=n;++i)
{
st[i][j][0]=max(st[i][j-1][0],st[i+(1<<j-1)][j-1][0]);
st[i][j][1]=min(st[i][j-1][1],st[i+(1<<j-1)][j-1][1]);
}
}
}
inline int qmax(int x,int y)
{
int s=_log[y-x+1];
return max(st[x][s][0],st[y-(1<<s)+1][s][0]);
}
inline int qmin(int x,int y)
{
int s=_log[y-x+1];
return min(st[x][s][1],st[y-(1<<s)+1][s][1]);
}
void dfs1(int x,int f,int d)
{
fa[x]=f;
dep[x]=d+1;
sz[x]=1;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f)
continue;
wt[y]=w[i];
dfs1(y,x,d+1);
sz[x]+=sz[y];
if(sz[y]>sz[son[x]])
son[x]=y;
}
}
void dfs2(int x,int t)
{
id[x]=++cnt;
top[x]=t;
seq[cnt]=x;
if(!son[x])
return;
dfs2(son[x],t);
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa[x]||y==son[x])
continue;
dfs2(y,y);
}
}
inline int querymin(int x,int y)
{
int ans=0x3f3f3f3f;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
ans=min(ans,qmin(id[top[x]],id[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
if(x==y)
return ans;
return min(ans,qmin(id[x]+1,id[y]));
}
inline int querymax(int x,int y)
{
int ans=-0x3f3f3f3f;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
ans=max(ans,qmax(id[top[x]],id[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
if(x==y)
return ans;
return max(ans,qmax(id[x]+1,id[y]));
}
int main()
{
read(n);
int u,v,f;
for(int i=1;i<n;++i)
{
read(u);
read(v);
read(f);
add(u,v,f);
add(v,u,f);
}
dfs1(1,1,1);
dfs2(1,1);
build();
read(m);
++m;
while(--m)
{
read(u);
read(v);
printf("%d %d\n",querymin(u,v),querymax(u,v));
}
return 0;
}

 评论

载入天数...载入时分秒...


博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议

本站使用 Material X 作为主题 , 总访问量为 次 。