BZOJ4336 骑士的旅行

Link

Difficulty

算法难度5,思维难度4,代码难度6

Description

给你一棵树,再给你一堆骑士,每个骑士有居住地和武力值

有3种操作:

  1. 查询x到y的路上,前K大的骑士的武力值
  2. 修改第i个骑士的居住地
  3. 修改第i个骑士的武力值

1 ≤ n ≤ 4 ∗ 1 0 4 , 1 ≤ K ≤ 20 1\le n\le 4*10^4,1\le K\le 20 1n4104,1K20

Solution

看K这么小,直接暴力树剖线段树维护咯

就维护线段树上每个点的前K大

然后树上每个点存这个点的所有的骑士

存的时候就用multiset就好了,注意删除

时间复杂度 O ( n k l o g 2 n ) O(nklog^2n) O(nklog2n)

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<set>
#define LL long long
using namespace std;
inline int read(){
    int x=0,f=1;char ch=' ';
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return f==1?x:-x;
}
const int N=1e5+5;
int n,m,q,k,tot;
int head[N],to[N],Next[N];
inline void addedge(int x,int y){
    to[++tot]=y;
    Next[tot]=head[x];
    head[x]=tot;
}
int size[N],heavy[N],top[N],father[N],dfn[N],dfn_clock,dep[N];
inline void dfs(int x,int fa){
    size[x]=1;father[x]=fa;dep[x]=dep[fa]+1;
    for(int i=head[x];i;i=Next[i]){
        int u=to[i];
        if(u==fa)continue;
        dfs(u,x);
        size[x]+=size[u];
        if(size[u]>size[heavy[x]])heavy[x]=u;
    }
}
inline void dfs2(int x,int first){
    top[x]=first;
    dfn[x]=++dfn_clock;
    if(size[x]==1)return;
    dfs2(heavy[x],first);
    for(int i=head[x];i;i=Next[i]){
        int u=to[i];
        if(u==father[x] || u==heavy[x])continue;
        dfs2(u,u);
    }
}
struct data{
    int len,a[21];
    data(){len=0;memset(a,0,sizeof a);}
    inline data operator + (const data& b) const {
        data ans;
        ans.len=min(k,len+b.len);
        for(int i=1,j=1,k=1;i<=ans.len;++i){
            if(j<=len && k<=b.len && a[j]>=b.a[k]){
                ans.a[i]=a[j];
                ++j;
            }
            else if(j<=len && k<=b.len && b.a[k]>a[j]){
                ans.a[i]=b.a[k];
                ++k;
            }
            else{
                if(j<=len){
                    ans.a[i]=a[j];
                    ++j;
                }
                else{
                    ans.a[i]=b.a[k];
                    ++k;
                }
            }
        }
        return ans;
    }
}d[N<<2];
multiset<int,greater<int> > s[N<<2];
int type;
inline void pushup(int rt){
    d[rt]=d[rt<<1]+d[rt<<1|1];
}
inline void insert(int rt,int l,int r,int pos,int v){
    if(l==r){
        if(type==1)s[rt].insert(v);
        else s[rt].erase(s[rt].lower_bound(v));
        d[rt].len=min(k,(int)s[rt].size());
        memset(d[rt].a,0,sizeof d[rt].a);
        int i=1;
        for(multiset<int>::iterator it=s[rt].begin();it!=s[rt].end();++it){
            d[rt].a[i]=*it;
            if(i==d[rt].len)break;
            ++i;
        }
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)insert(rt<<1,l,mid,pos,v);
    else insert(rt<<1|1,mid+1,r,pos,v);
    pushup(rt);
}
inline data query(int rt,int l,int r,int L,int R){
    if(L<=l && r<=R)return d[rt];
    int mid=(l+r)>>1;
    if(L<=mid && mid+1<=R)return query(rt<<1,l,mid,L,R)+query(rt<<1|1,mid+1,r,L,R);
    else if(L<=mid)return query(rt<<1,l,mid,L,R);
    else return query(rt<<1|1,mid+1,r,L,R);
}
inline data Query(int x,int y){
    data ans;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=ans+query(1,1,n,dfn[top[x]],dfn[x]);
        x=father[top[x]];
    }
    if(dep[x]<dep[y])swap(x,y);
    ans=ans+query(1,1,n,dfn[y],dfn[x]);
    return ans;
}
int V[N],X[N];
int main(){
    n=read();
    for(int i=1;i<n;++i){
        int x=read(),y=read();
        addedge(x,y);addedge(y,x);
    }
    dfs(1,0);
    dfs2(1,1);
    m=read();
    for(int i=1;i<=m;++i){
        V[i]=read();X[i]=read();
    }
    q=read();k=read();
    for(int i=1;i<=m;++i){
        type=1;insert(1,1,n,dfn[X[i]],V[i]);
    }
    for(int i=1;i<=q;++i){
        int opt=read(),x=read(),y=read();
        if(opt==1){
            data ans=Query(x,y);
            if(ans.len==0)printf("-1\n");
            else{
                for(int i=1;i<=ans.len;++i)printf("%d ",ans.a[i]);
                putchar('\n');
            }
        }
        else if(opt==2){
            type=2;insert(1,1,n,dfn[X[x]],V[x]);
            X[x]=y;
            type=1;insert(1,1,n,dfn[X[x]],V[x]);
        }
        else{
            type=2;insert(1,1,n,dfn[X[x]],V[x]);
            V[x]=y;
            type=1;insert(1,1,n,dfn[X[x]],V[x]);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值