HNOI2016 Day2 T2 网络<树链剖分>

题意

分析

考虑树链剖分。
用线段树搞,线段树上每个点开一个优先队列(大根对)。
每次有新的交互(u,v),就把不在(u,v)路径上的点加入一个v值。
查询时,就查这个点的top。

因为要删除,把优先队列换种写法,一个add队列,一个del队列,具体看代码。

应该是最好理解的做法了,但并不好打。

代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
using namespace std;
const int maxn=100000+10;
int n,m,q1[2*maxn],q2[2*maxn],q3[2*maxn];
//邻接表
struct Adjacency_list{
    int tot=0;          //总边数(从零开始计数,使得e的反向边为e^1)  
    int first[maxn];    //该点连的第一条边(最晚加进来的一条边) 
    struct edge{
        int to,next;
    }e[maxn];
    void init(int n){   //初始化0~n点的first 
        for(int i=0;i<=n;i++) first[i]=-1;
    }
    void addedge(int u,int v){ //在u与v之间连一条无边权的无向边(即u->v,v->u) 
        e[tot].to=v;
        e[tot].next=first[u];
        first[u]=tot++;
        e[tot].to=u;
        e[tot].next=first[v];
        first[v]=tot++;
    }
}a; 
//线段树
struct Segment_tree{
    priority_queue<int,vector<int>,less<int> > a[maxn*4],b[maxn*4];   //维护线段树每个点最大重要度,a维护加入,b维护删除 
    void Add(int u,int v) {
        //fprintf(stderr,"%d add %d\n",u,v);
        a[u].push(v);}
    void Del(int u,int v) {
        //fprintf(stderr,"%d del %d\n",u,v);
        b[u].push(v);}
    int Top(int u){
        while(!b[u].empty()&&b[u].top()==a[u].top())
          a[u].pop(),b[u].pop();
        if(a[u].empty()) return -1;
        else return a[u].top();
    }
    //把y1~y2的值加v(也可用来建树)
    int y1,y2,v;
    void update(int o,int l,int r){
        int lc=o*2,rc=o*2+1;         //左右儿子 
        int mid=(l+r)>>1;
        if(y1<=l&&y2>=r) Add(o,v);
        else{
            if(y1<=mid) update(lc,l,mid);
            if(y2>mid) update(rc,mid+1,r);
        }
    }
    //把y1~y2的值删去v
    void erase(int o,int l,int r){
        int lc=o*2,rc=o*2+1;         //左右儿子 
        int mid=(l+r)>>1;
        if(y1<=l&&y2>=r) Del(o,v);
        //if(y1<=l&&y2>=r&&o==1&&v==0) y1=y1;
        else{
            if(y1<=mid) erase(lc,l,mid);
            if(y2>mid) erase(rc,mid+1,r);
        }
    } 
    //查询y1
    int _max;
    void query(int o,int l,int r){
        if(l==r){
            _max=max(Top(o),_max);
            return;
        }
        else{
            int lc=o*2,rc=o*2+1;         //左右儿子 
            int mid=(l+r)>>1;
            _max=max(_max,Top(o));
            if(y1>mid) query(rc,mid+1,r);
            else query(lc,l,mid);
        }
    }
}l;
//树链剖分 
int dep[maxn],siz[maxn],fa[maxn],son[maxn],id[maxn],val[maxn],top[maxn];  //top最近的重链父节点 
int num;
void dfs1(int u,int f,int d){
    dep[u]=d;
    siz[u]=1;
    son[u]=0;
    fa[u]=f;
    for(int i=a.first[u];i!=-1;i=a.e[i].next){
        int v=a.e[i].to;
        if(v!=f){
            dfs1(v,u,d+1);
            siz[u]+=siz[v];
            if(siz[son[u]]<siz[v])
                son[u]=v;
        }
    } 
} 
void dfs2(int u,int tp){
    top[u]=tp;
    id[u]=++num;
    if(son[u]) dfs2(son[u],tp);
    for(int i=a.first[u];i!=-1;i=a.e[i].next){
        int v=a.e[i].to;
        if(v!=fa[u]&&v!=son[u]){
            dfs2(v,v);
        }
    }
}
//************************************************************************************************************ 
int totp;    
struct line{
    int l,r;
}p[25];
bool operator < (const line& l1,const line& l2){
    return l1.l<l2.l||(l1.l==l2.l&&l1.r<l2.r);
}
void find(int u,int v){
    if(top[u]==top[v])   //属于同一条重链
    {
        ++totp;
        p[totp].l=id[u];
        p[totp].r=id[v];
        if(p[totp].l>p[totp].r) swap(p[totp].l,p[totp].r);
    } 
    else{
        if(dep[top[u]]!=dep[top[v]]){
            if(dep[top[u]]<dep[top[v]]) swap(u,v);
            ++totp;
            p[totp].r=id[u];
            p[totp].l=id[top[u]];
            find(fa[top[u]],v);
        }
        else{
            ++totp;
            p[totp].r=id[u];
            p[totp].l=id[top[u]];
            ++totp;
            p[totp].r=id[v];
            p[totp].l=id[top[v]];
            find(fa[top[u]],fa[top[v]]);
        }
    }
}
void operation1(int u,int v,int w){
    totp=0;
    find(u,v);
    sort(p+1,p+totp+1);
    p[0].r=0;p[totp+1].l=n+1;
    for(int i=0;i<=totp;i++){
        l.y1=p[i].r+1;l.y2=p[i+1].l-1;l.v=w;
        if(l.y1<=l.y2) l.update(1,1,n);
    }
}
void operation2(int t){
    totp=0;
    find(q1[t],q2[t]);
    sort(p+1,p+totp+1);
    p[0].r=0;p[totp+1].l=n+1;
    for(int i=0;i<=totp;i++){
        l.y1=p[i].r+1;l.y2=p[i+1].l-1;l.v=q3[t];
        if(l.y1<=l.y2) l.erase(1,1,n);
    }
}
int operation3(int x){
    l._max=-1;
    l.y1=id[x];
    l.query(1,1,n);
    return l._max;
}
//************************************************************************************************************ 
int main()
{
    //freopen("network.in","r",stdin);
    //freopen("network.out","w",stdout);
    cin>>n>>m;
    a.init(n);
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        a.addedge(u,v); 
    }
    dfs1(1,0,1);
    dfs2(1,1);
    for(int i=1;i<=m;i++){
        int start;
        scanf("%d",&start);
        //int xxxx=operation3(3);
        //printf("(1)------》%d\n",xxxx); 
        if(start==0){
            scanf("%d%d%d",&q1[i],&q2[i],&q3[i]);
            operation1(q1[i],q2[i],q3[i]);
        }
        else if(start==1){
            int tt;
            scanf("%d",&tt);
            operation2(tt);
        }
        else{
            int xx;
            scanf("%d",&xx);
            printf("%d\n",operation3(xx));
        }
    }
    return 0;
} 
/*
13 23 
1 2 
1 3 
2 4 
2 5 
3 6 
3 7 
4 8 
4 9 
6 10 
6 11 
7 12 
7 13 
2 1 
0 8 13 3 
0 9 12 5 
2 9 
2 8 
2 2 
0 10 12 1 
2 2 
1 3 
2 7 
2 1 
0 9 5 6 
2 4 
2 5 
1 7 
0 9 12 4 
0 10 5 7 
2 1 
2 4 
2 12 
1 2 
2 5 
2 3
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值