校內賽 codeforces 827D【最小生成樹】【樹鏈剖分】 解題報告
阿新 • • 發佈:2018-12-24
找不到題面!!
題意
給出一張n(<=2e5)個點 m(<=2e5)條邊無向圖,保證有生成樹。對於每條邊,給出一個最大值maxLength,咦即能夠保證這條邊能夠出現在所有的最小生成樹中,邊權的最大值為maxLength(同時,其他所有邊長度不變)。給出所有m個答案。如果一條邊無論邊權是多大,都出現在所有最小生成樹中,則輸出-1.
思路
既然題面中出現了最小生成樹,那這就是必須的啦。所以,先最小生成樹跑一下,看看那些在樹上,這裡就是kruscal。
分類討論:
如果一條邊不在這棵樹上,那麼他可選的最大權值是它連線的樹上的兩點間最大權值-1。這一步可以倍增。
如果一條邊在這棵樹上,如果連線兩點間的路徑包含這條邊的所有邊的最小權值w,那麼他的最大權值就是w-1。每次將一條鏈上的邊權與給定值取min,最後求所有邊的邊權。這裡就是樹鏈剖分的事情了。
程式碼
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
const int N=400000+5;
const int inf=0x7fffffff;
int n,m,val[N],id[N],rk[N];
struct Edge
{
int v,next,w,id;
};
Edge e[2*N];
struct date
{
int u,v,w,id;
};
date aa[N];
int ans[N],fat[N],flag[N],head[N],num;
int find(int x)
{
return fat[x]==x?x:fat[x]=find(fat[x]);
}
void init()
{
for (int i=1;i<=n;i++)
fat[i]=i;
}
bool cmp(const date&a,const date&b)
{
return a.w<b.w;
}
bool cmp_id(const date&a,const date&b)
{
return a.id<b.id;
}
void adde(int i,int j,int w,int id)
{
e[++num].v=j;
e[num].next=head[i];
e[num].w=w;
e[num].id=id;
head[i]=num;
}
void Krus()
{
int cnt=0;
init();
sort(aa+1,aa+m+1,cmp);
for(int i=1;i<=m;i++)
{
int u=aa[i].u,v=aa[i].v,w=aa[i].w;
int p=find(u),q=find(v);
if (p==q) continue;
fat[p]=q;
adde(u,v,w,aa[i].id);
adde(v,u,w,aa[i].id);
flag[aa[i].id]=1;
cnt++;
if (cnt==n-1) break;
}
}
int dep[N],fa[N],top[N],son[N],idc,in[N],siz[N];
void dfs(int u)
{
siz[u]=1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==fa[u])continue;
fa[v]=u;
dep[v]=dep[u]+1;
val[v]=e[i].w;
id[v]=e[i].id;
dfs(v);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v])son[u]=v;
}
}
void dfs(int u,int tp){
in[u]=++idc;
rk[idc]=u;
top[u]=tp;
if(son[u])dfs(son[u],tp);
for(int i=head[u];i;i=e[i].next){
int v=e[i].v;
if(v==son[u]||v==fa[u])continue;
dfs(v,v);
}
}
struct Node
{
int vmax,id,lz;
Node *ls,*rs;
Node()
{
lz=inf;
}
void update()
{
vmax=max(ls->vmax,rs->vmax);
}
void pushdown(int lf,int rg)
{
if(lz!=inf)
{
ls->lz=min(ls->lz,lz);
rs->lz=min(rs->lz,lz);
lz=inf;
}
}
};
Node *root,pool[N*2],*tail=pool;
Node *build(int lf,int rg)
{
Node *nd=++tail;
if(lf==rg)
{
nd->id=id[rk[lf]];
nd->vmax=val[rk[lf]];
}
else
{
int mid=(lf+rg)>>1;
nd->ls=build(lf,mid);
nd->rs=build(mid+1,rg);
nd->update();
}
return nd;
}
int query_seg(Node *nd,int lf,int rg,int L,int R)
{
if (L<=lf&&rg<=R) return nd->vmax;
int mid=(lf+rg)>>1,rt=0;
if (L<=mid) rt=max(rt,query_seg(nd->ls,lf,mid,L,R));
if (R>mid) rt=max(rt,query_seg(nd->rs,mid+1,rg,L,R));
return rt;
}
void modify(Node *nd,int lf,int rg,int L,int R,int val)
{
if (L<=lf&&rg<=R) {nd->lz=min(nd->lz,val);return;}
int mid=(lf+rg)>>1;
if (L<=mid) modify(nd->ls,lf,mid,L,R,val);
if (R>mid) modify(nd->rs,mid+1,rg,L,R,val);
}
int query(int u,int v)
{
int rt=0;
while(top[u]!=top[v])
{
if (dep[top[u]]<dep[top[v]]) swap(u,v);
rt=max(rt,query_seg(root,1,n,in[top[u]],in[u]));
u=fa[top[u]];
}
if (u==v) return rt;
if (dep[u]<dep[v]) swap(u,v);
rt=max(rt,query_seg(root,1,n,in[son[v]],in[u]));
return rt;
}
void modify(int u,int v,int w)
{
while(top[u]!=top[v])
{
if (dep[top[u]]<dep[top[v]]) swap(u,v);
modify(root,1,n,in[top[u]],in[u],w);
u=fa[top[u]];
}
if (u==v) return;
if (dep[u]<dep[v]) swap(u,v);
modify(root,1,n,in[son[v]],in[u],w);
}
void get_ans(Node *nd,int lf,int rg)
{
if (lf==rg)
{
ans[nd->id]=nd->lz;
return;
}
nd->pushdown(lf,rg);
int mid=(lf+rg)>>1;
get_ans(nd->ls,lf,mid);
get_ans(nd->rs,mid+1,rg);
}
int main()
{
// freopen("tree.in","r",stdin);
// freopen("tree.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
scanf("%d%d%d",&aa[i].u,&aa[i].v,&aa[i].w),aa[i].id=i;
Krus();
sort(aa+1,aa+m+1,cmp_id);
fa[1]=0;dep[1]=1;
dfs(1);
dfs(1,1);
root=build(1,n);
for (int i=1;i<=m;i++)
{
if (flag[i]) continue;
ans[i]=query(aa[i].u,aa[i].v)-1;
modify(aa[i].u,aa[i].v,aa[i].w-1);
}
get_ans(root,1,n);
for (int i=1;i<=m;i++)
printf(ans[i]==inf?"-1\n":"%d\n",ans[i]);
return 0;
}