【题解】HNOI-2016网络

Problem

Let’s_boycott_bzoj

Solution

算是HNOI中比较简单的了……

这题一眼就是链剖,发现不能简单地线段树上标记覆盖修改,于是在线段树上的每一个节点上建一个堆,修改时如果修改区间,则直接在代表那个区间的线段树节点上插入即可,在修改时直接修改路径的补集,查询时要收集线段树上从根到那个节点一路上的堆顶值,这题唯一的难度就在代码要在短时间内打对吧(好像2016年的题都是这样?)

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rg register
#define cl(x) memset(x,0,sizeof(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define abs(x) ((x)>0?(x):(-(x)))

template <typename _Tp> inline _Tp read(_Tp&x){
    rg char c11=getchar(),ob=0;x=0;
    while(c11^'-'&&!isdigit(c11))c11=getchar();if(c11=='-')c11=getchar(),ob=1;
    while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;return x;
}

const int N=100100;
struct Edge{int v,nxt;}a[N<<1];
struct node{int l,r,w;}qu[N<<1];
int head[N],id[N],depth[N],sz[N],son[N],top[N],dad[N];
int n,m,_ans,_(0),cnt(0),rc(0);

struct HEAP{
    priority_queue <int> q1,q2;
    HEAP(){while(!q1.empty())q1.pop();while(!q2.empty())q2.pop();}
    inline void add(int x){q1.push(x);}
    inline void del(int x){q2.push(x);}
    inline int top(){
        while(!q2.empty())
            if(q1.top()==q2.top())
                q1.pop(),q2.pop();
            else break;
        if(!q1.empty())return q1.top();
        else return -1;
    }
}heap[N<<2];

struct Sequence{int l,r;inline bool operator < (const Sequence&b) const {return l<b.l;}}seq[N];

inline void add(int u,int v){
    a[++_].v=v,a[_].nxt=head[u],head[u]=_;
    a[++_].v=u,a[_].nxt=head[v],head[v]=_;
}

inline void dfs1(int x,int fa,int deep){
    depth[x]=deep,dad[x]=fa,sz[x]=1;
    rg int mxson(-1);
    for(rg int i=head[x];i;i=a[i].nxt)if(a[i].v!=fa){
        dfs1(a[i].v,x,deep+1);
        sz[x]+=sz[a[i].v];
        if(sz[a[i].v]>mxson)mxson=sz[son[x]=a[i].v];
    }
    return ;
}

inline void dfs2(int x,int Top){
    id[x]=++cnt;
    top[x]=Top;
    if(!son[x])return ;
    dfs2(son[x],Top);
    for(rg int i=head[x];i;i=a[i].nxt)
        if(a[i].v!=dad[x]&&a[i].v!=son[x])
            dfs2(a[i].v,a[i].v);
    return ;
}

#define mid ((l)+(r)>>1)

inline void update(int l,int r,int x,int L,int R,int alpha,int opt){
    if(L<=l&&r<=R){
        if(opt)heap[x].add(alpha);
        else heap[x].del(alpha);
        return ;
    }
    if(L<=mid)update(l,mid,x<<1,L,R,alpha,opt);
    if(mid<R)update(mid+1,r,x<<1|1,L,R,alpha,opt);
    return ;
}

inline void get_ans(int l,int r,int x,int pos){
    _ans=max(_ans,heap[x].top());
    if(l==r)return ;
    if(pos<=mid)get_ans(l,mid,x<<1,pos);
    else get_ans(mid+1,r,x<<1|1,pos);
    return ;
}

#undef mid

inline void ch_path(int x,int y,int alpha,int opt){
    rc=0;
    while(top[x]!=top[y]){
        if(depth[top[x]]<depth[top[y]])swap(x,y);
        seq[++rc].l=id[top[x]];
        seq[rc].r=id[x];
        x=dad[top[x]];
    }
    if(depth[x]>depth[y])swap(x,y);
    seq[++rc].l=id[x];seq[rc].r=id[y];
    sort(seq+1,seq+rc+1);
    rg int tl,tr,las(0);
    for(rg int i=1;i<=rc;++i){
        tl=las+1,tr=seq[i].l-1;
        if(tl<=tr)update(1,n,1,tl,tr,alpha,opt);
        las=seq[i].r;
    }
    tl=las+1,tr=n;
    if(tl<=tr)update(1,n,1,tl,tr,alpha,opt);
    return ;
}

int main(){
    read(n),read(m);
    for(rg int i=1,x,y;i<n;++i)add(read(x),read(y));
    rg int opt;

    dfs1(1,0,1);dfs2(1,1);

    for(rg int cas=1,x,y,z;cas<=m;++cas){
        read(opt);
        switch(opt){
            case 0:
                qu[cas].l=read(x);qu[cas].r=read(y);
                qu[cas].w=read(z);  ch_path(x,y,z,1);
                break;
            case 1:
                read(x);
                ch_path(qu[x].l,qu[x].r,qu[x].w,0);
                break;
            case 2:
                read(x);
                _ans=-1;
                get_ans(1,n,1,id[x]);
                printf("%d\n",_ans);
                break;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值