luogu1967货车运输题解--树链剖分

题目链接

https://www.luogu.org/problemnew/show/P1967

分析

NOIp的一道裸题,直接在最大生成树上剖分取最小值一下就完事了,非常好写,常数也比较小,然而题解里有许多我没见过的船新操作,先挖个坑等有时间再看

注意

  • 树链剖分又在第一遍挂了,忘了写top[now]=t;

  • 注意题目说明并没有保证是联通的!!!然后成功被Hack了.这真的要警惕,指不定哪天毒瘤出题人就在这里把你正解卡成60(flag++)

代码

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
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <vector>
#include <queue>
#define ll long ong
#define ri register int
#define ull unsigned long long
using std::vector;
using std::swap;
using std::min;
using std::max;
using std::sort;
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while(!isdigit(c=getchar()))ne=c=='-';
x=c-48;
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
x=ne?-x:x;return ;
}
const int maxn=10005;
const int maxm=50005;
const int inf=0x7fffffff;
int n,m;
struct Edge{
int x,y,c;
Edge(int _x,int _y,int _c){x=_x,y=_y,c=_c;}
Edge(){x=y=c=0;}
bool operator <(const Edge &b)const {
return c>b.c;
}
}edge[maxm];
struct Dat{
int ver,dis;
Dat(int x,int y){ver=x,dis=y;}
Dat(){;}
};
vector<Dat>g[maxn];
int pa[maxn];
int get(int x){
if(pa[x]!=x)pa[x]=get(pa[x]);//return pa[x]==x?pa[x]:pa[x]=get(pa[x]);
return pa[x];
}
inline void kruskal(){
int cnt=0,x,y,xx,yy,c;
sort(edge+1,edge+1+m);
for(ri i=1;i<=n;i++)pa[i]=i;
for(ri i=1;i<=m;i++){
//printf("%d\n",edge[i].c);
int x=edge[i].x,y=edge[i].y;
xx=get(x),yy=get(y);
if(xx==yy)continue;
c=edge[i].c;
//printf("%d %d %d\n",x,y,c);
g[x].push_back(Dat(y,c));
g[y].push_back(Dat(x,c));
pa[xx]=yy;
cnt++;
if(cnt==n-1)break;
}
return ;
}
int dep[maxn],son[maxn],top[maxn],size[maxn],dfn[maxn],fa[maxn],rnk[maxn],tot=0;
int w[maxn];
void dfs_1(int now){
int v;size[now]=1;
for(ri i=0;i<g[now].size();i++){
v=g[now][i].ver;
if(v==fa[now])continue;
fa[v]=now,dep[v]=dep[now]+1;
w[v]=g[now][i].dis;
dfs_1(v);
size[now]+=size[v];
if(!son[now]||size[v]>size[son[now]])son[now]=v;
}
return ;
}
void dfs_2(int now,int t){
int v;dfn[now]=++tot,rnk[tot]=now,top[now]=t;
if(!son[now])return ;
dfs_2(son[now],t);
for(ri i=0;i<g[now].size();i++){
v=g[now][i].ver;
if(v==fa[now]|v==son[now])continue;
dfs_2(v,v);
}
return ;
}
int mi[maxn<<2];
void build(int now,int l,int r){
if(l==r){
mi[now]=w[rnk[l]];
return ;
}
int mid=(l+r)>>1;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
mi[now]=min(mi[now<<1],mi[now<<1|1]);
return ;
}
int L,R;
int query(int now,int l,int r){
if(L<=l&&r<=R){
return mi[now];
}
int ans=inf,mid=(l+r)>>1;
if(L<=mid)ans=min(ans,query(now<<1,l,mid));
if(mid<R)ans=min(ans,query(now<<1|1,mid+1,r));
return ans;
}
inline int query_path(int x,int y){
int ans=inf;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
L=dfn[top[x]],R=dfn[x];
ans=min(ans,query(1,1,n));
x=fa[top[x]];
}
if(dfn[x]>dfn[y])swap(x,y);
L=dfn[x]+1,R=dfn[y];
if(L>R)return ans;
ans=min(ans,query(1,1,n));
return ans;
}
int main(){
int q,x,y,z;
read(n),read(m);
for(ri i=1;i<=m;i++){
read(x),read(y),read(z);
edge[i]=Edge(x,y,z);
}
kruskal();
for(ri i=1;i<=n;i++){//不一定联通
if(!dfn[i]){
dep[i]=1,fa[i]=0;
dfs_1(i);
dfs_2(i,i);
}
}
build(1,1,n);
read(q);
while(q--){
read(x),read(y);
int tmp=query_path(x,y);
if(!tmp)puts("-1");
else printf("%d\n",tmp);
}
return 0;
}