1. 程式人生 > >校內賽 codeforces 827D【最小生成樹】【樹鏈剖分】 解題報告

校內賽 codeforces 827D【最小生成樹】【樹鏈剖分】 解題報告

找不到題面!!

題意

給出一張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; }