【树剖】Disruption

题目链接<http://10.7.88.2/CLanguage/showproblem?problem_id=2266>


题意:

给出一棵树,和一些额外的边。询问树的每条边,把这条边断开,添加一条额外的边使原图仍然连通。如果存在这样的额外边,输出权值最小的,否则输出-1.


题解:

很容易想到,对于每一条额外边,这一段的简单路上的边都被更新答案,所以就是个树剖裸题。

注意:

  1. 题目求的是边权值,我把每条边都用下面的点表示,这样两点的lca不能被更新。
  2. dfs深度过万很可能爆栈,所以要人工写栈。
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define ll long long
using namespace std;
const int N=5e4+7;
const int inf=1e9+7;
int n;
int t[N<<2],lz[N<<2],tot;
void bd(int rt,int l,int r){
    t[rt]=inf;
    if(l==r) return;
    int m=l+r>>1;
    bd(rt<<1,l,m);
    bd(rt<<1|1,m+1,r);
}
void pd(int rt){
    if(lz[rt]){
        if(t[rt<<1]>t[rt]) t[rt<<1]=lz[rt<<1]=lz[rt];
        if(t[rt<<1|1]>t[rt]) t[rt<<1|1]=lz[rt<<1|1]=lz[rt];
        lz[rt]=0;
    }
}
void upd(int rt,int l,int r,int L,int R,int val){
    if(L>R) return;
    if(L<=l&&r<=R){
        if(t[rt]>val) lz[rt]=t[rt]=val;
        return;
    }
    pd(rt);
    int m=l+r>>1;
    if(L<=m) upd(rt<<1,l,m,L,R,val);
    if(m<R) upd(rt<<1|1,m+1,r,L,R,val);
    t[rt]=max(t[rt<<1],t[rt<<1|1]);
}
int que(int rt,int l,int r,int x){
    if(l==r) return t[rt];
    pd(rt);
    int m=l+r>>1;
    if(x<=m) return que(rt<<1,l,m,x);
    else return que(rt<<1|1,m+1,r,x);
}


struct Edge{
    int v,id,nxt;
}e[N*2];
int p[N],edn;
void add(int u,int v,int id){
    e[++edn]=(Edge){v,id,p[u]};p[u]=edn;
    e[++edn]=(Edge){u,id,p[v]};p[v]=edn;
}


int id[N];
struct Node{
    int dt,hs,sz,fa;
    int ps,tp;
}a[N];
void dfs(int u){
    a[u].dt=a[a[u].fa].dt+1;
    a[u].hs=0;
    a[u].sz=1;
    int mx=0;
    for(int i=p[u];~i;i=e[i].nxt){
        int v=e[i].v;
        if(v==a[u].fa) continue;
        a[v].fa=u;id[v]=e[i].id;dfs(v);
        if(a[v].sz>mx) mx=a[v].sz,a[u].hs=v;
        a[u].sz+=a[v].sz;
    }
}
void dfs(){
    int su[N],si[N],mx[N],top;
    for(int i=1;i<=n;i++) si[i]=p[i],mx[i]=0;
    su[1]=1; top=1;
    a[1].fa=0; a[1].dt=1; a[1].hs=0; a[1].sz=1;
    int u,v;
    while(1){
        u=su[top];
        while(~si[u]){
            v=e[si[u]].v;
            if(a[v].sz) si[u]=e[si[u]].nxt;
            else break;
        }
        if(si[u]==-1){
            top--; if(top==0) break;
            v=u;u=su[top];
            if(a[v].sz>mx[u]) mx[u]=a[v].sz,a[u].hs=v;
            a[u].sz+=a[v].sz;
        }
        else{
            a[v].fa=u;id[v]=e[si[u]].id;
            a[v].dt=a[u].dt+1;a[v].hs=0;a[v].sz=1;
            su[++top]=v;
            si[u]=e[si[u]].nxt;
        }
    }
}
void bdfs(int u,int k){
    a[u].tp=k;
    a[u].ps=++tot;
    if(a[u].hs) bdfs(a[u].hs,k);
    for(int i=p[u];~i;i=e[i].nxt){
        int v=e[i].v;
        if(v==a[u].fa||v==a[u].hs) continue;
        bdfs(v,v);
    }
}
void bdfs(){
    int su[N],si[N],top=1;
    bool vis[N];
    for(int i=1;i<=n;i++) vis[i]=false,si[i]=p[i];
    tot=0;
    su[1]=1;
    a[1].tp=1;a[1].ps=++tot;
    int u,v;
    while(1){
        u=su[top];
        if(a[u].hs&&!vis[u]){
            v=a[u].hs;
            top++;su[top]=v;
            a[v].tp=a[u].tp;
            a[v].ps=++tot;
            vis[u]=true;
            continue;
        }
        while(~si[u]){
            v=e[si[u]].v;
            if(a[v].ps||v==a[u].hs) si[u]=e[si[u]].nxt;
            else break;
        }
        if(si[u]==-1){
            top--; if(top==0) break;
        }
        else{
            top++;su[top]=v;
            a[v].tp=v;
            a[v].ps=++tot;
        }
    }
}
void upd(int x,int y,int val){
    int xx=a[x].tp,yy=a[y].tp;
    while(xx!=yy){
        if(a[xx].dt>=a[yy].dt){
            upd(1,1,n,a[xx].ps,a[x].ps,val);
            x=a[xx].fa;
        }
        else{
            upd(1,1,n,a[yy].ps,a[y].ps,val);
            y=a[yy].fa;
        }
        xx=a[x].tp,yy=a[y].tp;
    }
    if(a[x].dt<a[y].dt) upd(1,1,n,a[x].ps+1,a[y].ps,val);
    else if(a[x].dt>a[y].dt) upd(1,1,n,a[y].ps+1,a[x].ps,val);
}
int pr[N];
int main()
{
    int m,u,v,w;
    scanf("%d%d",&n,&m);
    memset(p,-1,sizeof(p));edn=-1;
    for(int i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        add(u,v,i);
    }
    dfs();
    bdfs();
    bd(1,1,n);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&u,&v,&w);
        upd(u,v,w);
    }
    for(int i=2;i<=n;i++){
        pr[id[i]]=que(1,1,n,a[i].ps);
    }
    for(int i=1;i<n;i++){
        if(pr[i]>=inf) printf("-1\n");
        else printf("%d\n",pr[i]);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值