树链剖分+segtree+treap HYSBZ 1146 网络管理Network

题目很好理解,因为是汉语的。。。

就是求树上的一条路径的第K大数,可修改,多组询问,当然了,对于每组询问,o(n)的时间复杂度不能接受,只能是log级别的

所以就是树链剖分,加segtree套平衡树,代码挺长的

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
#define mid (L+R>>1)
const int inf=~0u>>1;
const int M = 80010;
class Treap{
public:
    struct node{
        node *ch[2];
        int v,p,sz;
        node(int _v,node *n):
            v(_v){ch[0]=ch[1]=n;p=rand();sz=1;}
        void update(){sz=ch[0]->sz+ch[1]->sz+1;}
    };
    node *root,*null;
    Treap(){
        null=new node(0,0);null->sz=0;null->p=inf;
        null->ch[0]=null->ch[1]=null;
        root=null;
    }
    void rotate(node *&t,bool d){
        node *_t=t->ch[d];
        t->ch[d]=_t->ch[!d];
        _t->ch[!d]=t;
        _t->update();
        t->update();
        t=_t;
    }
    void __insert(node *&t,int val){
        if(t==null){
            t=new node(val,null);
            return;
        }
        bool d=val > t->v;
        __insert(t->ch[d],val);
        if(t->ch[d]->p < t->p)rotate(t,d);
        t->update();
    }
    void __del(node *&t,int val){
        if(t==null)return;
        if(val == t->v){
            bool d = t->ch[1]->p < t->ch[0]->p;
            if(t->ch[d]==null){
                delete t;
                t=null;
                return;
            }
            rotate(t,d);
            __del(t->ch[!d],val);
        }else{
            bool d=val > t->v;
            __del(t->ch[d],val);
        }
        t->update();
    }
    int __rank(node *t,int val){
        if(t==null)return 0;
        if(val > t->v)return __rank(t->ch[1],val);
        return t->ch[1]->sz+1+__rank(t->ch[0],val);
    }
    void insert(int val){
        __insert(root,val);
    }
    void del(int val){
        __del(root,val);
    }
    int rank(int val){
        return __rank(root,val);
    }
};
class segtree{
public:
    Treap *tree[M<<2];
    int val[M];
    void build(int L,int R,int P){
        tree[P] = new Treap;
        for(int i=L;i<=R;i++){
            tree[P]->insert(val[i]);
        }
        if(L==R)return ;
        build(L,mid,P<<1);
        build(mid+1,R,P<<1|1);
    }
    int query(int L,int R,int P,int l,int r,int val){
        if(L==l&&R==r){
            return tree[P]->rank(val);
        }
        int ret=0;
        if(l<=mid){
            ret+=query(L,mid,P<<1,l,min(mid,r),val);
        }
        if(r>mid){
            ret+=query(mid+1,R,P<<1|1,max(l,mid+1),r,val);
        }
        return ret;
    }
    void update(int L,int R,int P,int p,int a,int b){
        tree[P]->del(a);
        tree[P]->insert(b);
        if(L==R)return ;
        if(p<=mid){
            update(L,mid,P<<1,p,a,b);
        }else{
            update(mid+1,R,P<<1|1,p,a,b);
        }
    }
};
int head[M],cnt;
struct Edge{
    int u,v,next;
    void set(int _u,int _v){
        u=_u,v=_v;
        next=head[u];
        head[u]=cnt++;
    }
}edge[M<<1];
segtree *tree;
int son[M],pre[M],dep[M],siz[M],top[M],pos[M],tot;
int val[M],n,m;
 
void init(){
    cnt=tot=0;
    memset(head,-1,sizeof(head));
}
void dfs_1(int u,int f,int d){
    pre[u]=f,dep[u]=d;
    siz[u]=1,son[u]=0;
    for(int i=head[u];~i;i=edge[i].next){
        int v=edge[i].v;
        if(v!=f){
            dfs_1(v,u,d+1);
            siz[u]+=siz[v];
            if(siz[son[u]]<siz[v])son[u]=v;
        }
    }
}
void dfs_2(int u,int tp){
    top[u]=tp,pos[u]=++tot;
    if(son[u])dfs_2(son[u],tp);
    for(int i=head[u];~i;i=edge[i].next){
        int v=edge[i].v;
        if(v!=son[u]&&v!=pre[u])dfs_2(v,v);
    }
}
int rank(int u,int v,int vall){
    int f1=top[u],f2=top[v],ret=0;
    while(f1!=f2){
        if(dep[f1]<dep[f2])swap(u,v),swap(f1,f2);
        ret+=tree->query(1,n,1,pos[f1],pos[u],vall);
        u=pre[f1],f1=top[u];
    }
    if(dep[u]<dep[v])swap(u,v);
    return ret+tree->query(1,n,1,pos[v],pos[u],vall);
}
int main(){
    while(~scanf("%d%d",&n,&m)){
        init();
        for(int i=1;i<=n;i++){
            scanf("%d",&val[i]);
        }
        for(int i=1,u,v;i<n;i++){
            scanf("%d%d",&u,&v);
            edge[cnt].set(u,v);
            edge[cnt].set(v,u);
        }
        tree = new segtree;
        dfs_1(1,0,1);
        dfs_2(1,1);
        for(int i=1;i<=n;i++){
            tree->val[pos[i]]=val[i];
        }
        tree->build(1,n,1);
        while(m--){
            int k,a,b;
            scanf("%d%d%d",&k,&a,&b);
            if(k){
                int L=0,R=(int)1e8,f=0;
                while(L<=R&&!f){
                    int aa=rank(a,b,mid+1);
                    int bb=rank(a,b,mid);
                    if(k>aa&&k<=bb){
                        f=1;
                        printf("%d\n",mid);
                    }
                    k>aa?R=mid-1:L=mid+1;   
                }
                if(!f)puts("invalid request!");
            }else{
                tree->update(1,n,1,pos[a],val[a],b);
                val[a]=b;
            }
        }
    }
    return 0;   
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值