HNOI 2016 网络

网络

特点

利用树剖+线段树+可删除堆(双堆),维护不经过某个点的最大值

具体操作

1.预处理树剖。
2.线段树每个节点一个可删除堆(两个堆)。
3.对于加边操作,树剖跳出了一个个线段,都存下来,此时这些线段表示的是这条链,那么除去这些线段表示的就是其他点。更新除这些线段以为的线段即可。

具体代码

#include<bits/stdc++.h>
using namespace std;
const int M=1e5+5;
int n,m;
struct Query {
    int a,b,v;
} Qu[M*2];
vector<int>G[M];
struct Priority {
    priority_queue<int>Q1,Q2;
    int top() {
        while(!Q1.empty()&&!Q2.empty()) {
            if(Q1.top()==Q2.top())Q1.pop(),Q2.pop();
            else return Q1.top();
        }
        if(Q1.empty())return -1;
        else return Q1.top();
    }
    void push(int x,int tp) {
        if(tp==1)Q1.push(x);
        else Q2.push(x);
    }
} Q[M*4];
int top[M],sz[M],dfn[M],DR[M],tot,fa[M],dep[M],son[M];
void dfs1(int x,int f) {
    fa[x]=f;
    son[x]=0;
    dep[x]=dep[f]+1;
    sz[x]=1;
    for(int i=0; i<G[x].size(); i++) {
        int y=G[x][i];
        if(y==f)continue;
        dfs1(y,x);
        sz[x]+=sz[y];
        if(sz[y]>sz[son[x]])son[x]=y;
    }
}
void dfs2(int x,int tp) {
    top[x]=tp;
    dfn[x]=++tot;
    if(son[x])dfs2(son[x],tp);
    for(int i=0; i<G[x].size(); i++) {
        int y=G[x][i];
        if(y==fa[x]||y==son[x])continue;
        dfs2(y,y);
    }
    DR[x]=tot;
}
struct Sem {
    int L,R;
    void rd(int a,int b) {
        L=a,R=b;
    }
    bool operator <(const Sem&tmp)const {
        return L<tmp.L;
    }
} B[M];
void update(int l,int r,int v,int tp,int L,int R,int p) {
    if(l==L&&r==R) {
        Q[p].push(v,tp);
        return;
    }
    int mid=L+R>>1;
    if(r<=mid)update(l,r,v,tp,L,mid,p<<1);
    else if(mid<l)update(l,r,v,tp,mid+1,R,p<<1|1);
    else {
        update(l,mid,v,tp,L,mid,p<<1);
        update(mid+1,r,v,tp,mid+1,R,p<<1|1);
    }
}
void Update(int a,int b,int v,int tp) {
    int len=0;
    while(top[a]!=top[b]) {
        if(dep[top[a]]<dep[top[b]])swap(a,b);
        B[++len].rd(dfn[top[a]],dfn[a]);
        a=fa[top[a]];
    }
    if(dep[a]>dep[b])swap(a,b);
    if(dfn[a]+1<=dfn[b])B[++len].rd(dfn[a],dfn[b]);
    sort(B+1,B+1+len);
    B[0].R=0;
    B[++len].L=n+1;
    for(int i=0; i<len; i++) {
        if(B[i].R+1<=B[i+1].L-1) {
            update(B[i].R+1,B[i+1].L-1,v,tp,1,n,1);
        }
    }
}
int query(int x,int L,int R,int p) {
    if(L==R)return Q[p].top();
    int mid=L+R>>1;
    if(x<=mid)return max(Q[p].top(),query(x,L,mid,p<<1));
    else return max(Q[p].top(),query(x,mid+1,R,p<<1|1));
}
int main() {
    int a,b,c,tp;
    scanf("%d %d",&n,&m);
    for(int i=1; i<n; i++) {
        scanf("%d %d",&a,&b);
        G[a].push_back(b);
        G[b].push_back(a);
    }
    dfs1(1,0);
    dfs2(1,1);
    for(int i=1; i<=m; i++) {
        scanf("%d",&tp);
        if(tp==0) {
            scanf("%d %d %d",&a,&b,&c);
            Qu[i].a=a,Qu[i].b=b,Qu[i].v=c;
            Update(a,b,c,1);
        } else if(tp==1) {
            scanf("%d",&a);
            Update(Qu[a].a,Qu[a].b,Qu[a].v,-1);
        } else {
            scanf("%d",&a);
            printf("%d\n",query(dfn[a],1,n,1));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值