bzoj 3732 Network(最短路+倍增 | LCT)

【题目链接】

http://www.lydsy.com/JudgeOnline/problem.php?id=3732

【题意】

给定一个无向图,处理若干询问:uv路径上最长的边最小是多少?

【思路一】

最小生成树+倍增算法。

同NOIP2013货车运输。

【代码】

 #include<set>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std; typedef long long ll;
const int N = 1e5+;
const int M = 2e5+;
const int D = ;
const int inf = 2e9; ll read() {
char c=getchar();
ll f=,x=;
while(!isdigit(c)) {
if(c=='-') f=-; c=getchar();
}
while(isdigit(c))
x=x*+c-'',c=getchar();
return x*f;
} struct Edge {
int u,v,w,nxt;
bool operator < (const Edge& rhs) const{
return w<rhs.w;
}
}e[M];
int en=,front[N];
void adde(int u,int v,int w)
{
e[++en]=(Edge){u,v,w,front[u]}; front[u]=en;
}
vector<Edge> es; int n,m,K,p[N],_max[N][D],fa[N][D],dep[N]; int ifind(int u)
{
return u==p[u]? u:p[u]=ifind(p[u]);
} void Kruskal()
{
sort(es.begin(),es.end());
FOR(i,,(int)es.size()-) {
int u=es[i].u,v=es[i].v,w=es[i].w;
int x=ifind(u),y=ifind(v);
if(x!=y) {
p[x]=y;
adde(u,v,w); adde(v,u,w);
}
}
}
void dfs(int u,int father)
{
trav(u,i) {
int v=e[i].v;
if(v!=father) {
fa[v][]=u;
_max[v][]=e[i].w;
dep[v]=dep[u]+;
FOR(j,,D-) {
fa[v][j]=fa[fa[v][j-]][j-];
_max[v][j]=max(_max[v][j-],_max[fa[v][j-]][j-]);
}
dfs(v,u);
}
}
} int query(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
int t=dep[u]-dep[v],ans=-inf;
FOR(i,,D-)
if(t&(<<i)) {
ans=max(ans,_max[u][i]);
u=fa[u][i];
}
if(u==v) return ans;
for(int i=D-;i>=;i--)
if(fa[u][i]!=fa[v][i]) {
ans=max(ans,max(_max[u][i],_max[v][i]));
u=fa[u][i],v=fa[v][i];
}
ans=max(ans,max(_max[u][],_max[v][]));
return ans;
} int main()
{
n=read(),m=read(),K=read();
FOR(i,,n) FOR(j,,D-) _max[i][j]=-inf;
FOR(i,,n) p[i]=i;
FOR(i,,m) {
int u=read(),v=read(),w=read();
es.push_back((Edge){u,v,w,});
}
Kruskal();
dfs(,-);
FOR(i,,K) {
int u=read(),v=read();
printf("%d\n",query(u,v));
}
return ;
}

【思路二】

用LCT换个姿势AC。LCT维护最小生成树?

给每条边每个点开一个LCT结点,边的maxe初始为自己,点的maxe为0。对于新加的一条边,找到u->v目前的最大边与之比较,如果更小则切断原来的边连上新的边。u,v之间连边的时候以边界点为中间点。

【代码】

 #include<cstdio>
#include<cstring>
#include<iostream>
#define FOR(a,b,c) for(int a=b;a<=c;a++)
#define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
using namespace std; typedef long long ll;
typedef unsigned int ul;
const int N = 4e5+; ll read() {
char c=getchar();
ll f=,x=;
while(!isdigit(c)) {
if(c=='-') f=-; c=getchar();
}
while(isdigit(c))
x=x*+c-'',c=getchar();
return x*f;
} struct Edge { int u,v,w;
}e[N<<]; namespace LCT { struct Node {
Node *ch[],*fa;
int rev,id,maxe;
Node() ;
void reverse() {
rev^=;
swap(ch[],ch[]);
}
void up_push() {
if(fa->ch[]==this||fa->ch[]==this)
fa->up_push();
if(rev) {
ch[]->reverse();
ch[]->reverse();
rev=;
}
}
void maintain() {
int _max=-;
if(e[ch[]->maxe].w>_max)
_max=e[ch[]->maxe].w,maxe=ch[]->maxe;
if(e[ch[]->maxe].w>_max)
_max=e[ch[]->maxe].w,maxe=ch[]->maxe;
if(e[id].w>_max) maxe=id;
}
} *null=new Node,T[N],E[N<<];
Node::Node() {
id=maxe=rev=;
fa=ch[]=ch[]=null;
} void rot(Node* o,int d) {
Node *p=o->fa;
p->ch[d]=o->ch[d^];
o->ch[d^]->fa=p;
o->ch[d^]=p;
o->fa=p->fa;
if(p==p->fa->ch[])
p->fa->ch[]=o;
else if(p==p->fa->ch[])
p->fa->ch[]=o;
p->fa=o;
p->maintain();
}
void splay(Node *o) {
o->up_push();
Node *nf,*nff;
while(o->fa->ch[]==o||o->fa->ch[]==o) {
nf=o->fa,nff=nf->fa;
if(o==nf->ch[]) {
if(nf==nff->ch[]) rot(nf,);
rot(o,);
} else {
if(nf==nf->ch[]) rot(nf,);
rot(o,);
}
}
o->maintain();
}
void Access(Node* o) {
Node *son=null;
while(o!=null) {
splay(o);
o->ch[]=son;
o->maintain();
son=o; o=o->fa;
}
}
void evert(Node* o) {
Access(o);
splay(o);
o->reverse();
}
void Link(Node* u,Node* v) {
evert(u);
u->fa=v;
}
void Cut(Node* u,Node* v) {
evert(u);
Access(v); splay(v);
u->fa=v->ch[]=null;
v->maintain();
}
Node* find(Node* o) {
while(o->fa!=null) o=o->fa;
return o;
} }
using namespace LCT; const int inf = 1e9+; int n,m,K; int query(Node *u,Node *v)
{
evert(u);
Access(v),splay(v);
return v->maxe;
}
void insert(Node *u,Node *v,int x)
{
if(e[x].u==e[x].v) return ;
if(find(u)==find(v)) {
int maxe=query(u,v);
if(e[x].w>=e[maxe].w) return ;
Cut(&E[maxe],&T[e[maxe].v]);
Cut(&E[maxe],&T[e[maxe].u]);
}
Link(u,&E[x]);
Link(v,&E[x]);
} int main()
{
n=read(),m=read(),K=read();
FOR(i,,m) E[i].id=E[i].maxe=i;
FOR(i,,m) {
e[i].u=read(),e[i].v=read(),e[i].w=read();
insert(&T[e[i].u],&T[e[i].v],i);
}
FOR(i,,K) {
int u=read(),v=read();
printf("%d\n",e[query(&T[u],&T[v])].w);
}
return ;
}
上一篇:MIUI9 解锁并刷入TWRP后,删除解锁密码


下一篇:移植lrzsz串口文件传输工具到mini2440