洛谷.4172.[WC2006]水管局長(LCT Kruskal)
阿新 • • 發佈:2018-03-30
處理 pushd 重新 需要 樹邊 IT || 路徑 max
題目鏈接 洛谷(COGS上也有)
不想去做加強版了。。(其實處理一下矩陣就好了)
題意: 有一張圖,求一條x->y的路徑,使得路徑上最長邊盡量短並輸出它的長度。會有<=5000次刪邊。
這實際上就是動態地維護MST。用LCT維護MST,路徑詢問也能直接查詢,每次刪邊看這條邊是否在MST上。
只有1000個點!邊直接矩陣存。
而且刪邊次數很少,於是最初想的是每次刪邊用堆優化Prim O(nlogn)重新求一遍MST。但是5000100010=5e7。。(也許行吧)
日常刪邊改成加邊,離線即可。加邊時MST上的求路徑Max,看是否需要Cut,重新Link.(正序的話還要找一遍沒被刪的連接兩集合的最小邊)
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define MAXIN (200000)
const int N=1005,M=1e5+5,S=N+M;//雖然維護的是MST但大小還是要M的。。當然可以記錄每條樹邊並循環利用,以後再寫吧。。
int n,m,type[M],ff[N],qx[M],qy[M],id[N][N],Ans[M];
char IN[MAXIN],*SS=IN,*TT=IN;
bool ban[M];
struct Edge{
int fr,to,val;
Edge() {}
Edge(int f,int t,int v):fr(f),to(t),val(v) {}
bool operator <(const Edge &a)const{
return val<a.val;
}
}e[M];
namespace LCT
{
#define lson son[x][0]
#define rson son[x][1]
int pos[S],val[S],son[S][2],fa[S],sk[S];
bool rev[S];
inline int Get(int x,int y){
return val[x]>val[y]?x:y;
}
inline void Update(int x){
pos[x]=Get(x,Get(pos[lson],pos[rson]));//是左右兒子的pos!又一次寫錯。。
}
inline bool n_root(int x){
return son[fa[x]][0]==x||son[fa[x]][1]==x;
}
inline void Rev(int x){
std::swap(lson,rson), rev[x]^=1;
}
void PushDown(int x){
if(rev[x]) Rev(lson),Rev(rson),rev[x]=0;
}
void Rotate(int x)
{
int a=fa[x],b=fa[a],l=son[a][1]==x,r=l^1;
if(n_root(a)) son[b][son[b][1]==a]=x;
if(son[x][r]) fa[son[x][r]]=a;
fa[a]=x, fa[x]=b, son[a][l]=son[x][r], son[x][r]=a;
Update(a);
}
void Splay(int x)
{
int t=1,a=x; sk[1]=x;
while(n_root(a)) sk[++t]=a=fa[a];
while(t) PushDown(sk[t--]);
while(n_root(x))
{
if(n_root(a=fa[x])) Rotate(son[a][1]==x^son[fa[a]][1]==a?x:a);
Rotate(x);
}
Update(x);
}
void Access(int x){
for(int pre=0; x; x=fa[pre=x])
Splay(x), rson=pre, Update(x);
}
void Make_root(int x){
Access(x), Splay(x), Rev(x);
}
void Split(int x,int y){
Make_root(x), Access(y), Splay(y);
}
int Find_root(int x)
{
Access(x), Splay(x);
while(lson) x=lson;
return x;
}
void Link(int x){//在合法的情況下Find_root()並不是必須的(不維護子樹信息的話?)
Make_root(e[x].to), fa[fa[e[x].to]=x+N]=e[x].fr;
val[x+N]=e[x].val, Update(x+N);
}
void Cut(int x){//註意這的編號
Access(e[x-N].to), Splay(x), lson=rson=fa[lson]=fa[rson]=0;
}
}
using namespace LCT;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
int Get_fa(int x){
return x==ff[x]?x:ff[x]=Get_fa(ff[x]);
}
int main()
{
n=read(),m=read();int Q=read();
for(int x,y,i=1; i<=m; ++i) x=read(),y=read(),e[i]=Edge(x,y,read());
std::sort(e+1,e+1+m);//先排序再編號!
for(int i=1; i<=m; ++i) id[e[i].fr][e[i].to]=id[e[i].to][e[i].fr]=i;
for(int i=1; i<=Q; ++i)
{
type[i]=read(),qx[i]=read(),qy[i]=read();
if(type[i]==2) ban[id[qx[i]][qy[i]]]=1;
}
for(int i=1; i<=n; ++i) ff[i]=i;
for(int t,x,y,k=0,i=1; i<=m; ++i)
if(!ban[t=id[x=e[i].fr][y=e[i].to]] && Get_fa(x)!=Get_fa(y))
{//不需要記r1,r2
ff[ff[x]]=ff[y], Link(t);
if(++k==n) break;
}
int cnt=0;
for(int i=Q,x,y,t; i; --i)
{
Split(x=qx[i],y=qy[i]);
if(type[i]==1) Ans[++cnt]=val[pos[y]];
else if(t=id[x][y],val[pos[y]]>e[t].val){
Cut(pos[y]), Link(t);
}
}
while(cnt) printf("%d\n",Ans[cnt--]);
return 0;
}
洛谷.4172.[WC2006]水管局長(LCT Kruskal)