[BZOJ]4336: BJOI2015 骑士的旅行 树链剖分+STL(multiset)

Description

在一片古老的土地上,有一个繁荣的文明。
这片大地几乎被森林覆盖,有N座城坐落其中。巧合的是,这N座城由恰好N-1条双向道路连接起来,使得任意两座城都是连通的。也就是说,这些城形成了树的结构,任意两座城之间有且仅有一条简单路径。在这个文明中,骑士是尤其受到尊崇的职业。任何一名骑士,都是其家族乃至家乡的荣耀。Henry从小就渴望成为一名能守护家乡、驱逐敌人的骑士。勤奋训练许多年后,Henry终于满18岁了。他决定离开家乡,向那些成名已久的骑士们发起挑战!根据Henry的调查,大陆上一共有M名受封骑士,不妨编号为1到M。第i个骑士居住在城Pi,武力值为Fi。Henry计划进行若干次旅行,每次从某座城出发沿着唯一的简单路径前往另一座城,同时会挑战路线上武力值最高的K个骑士(Henry的体力有限,为了提高水平,当然要挑战最强的骑士)。如果路线上的骑士不足K人,Henry会挑战遇到的所有人。每次旅行前,可能会有某些骑士的武力值或定居地发生变化,Henry自然会打听消息,并对计划做出调整。
为了在每次旅行时做好充分准备,Henry希望你能帮忙在每次旅行前计算出这条路线上他将挑战哪些对手。

题解:

%%%zyf2000,因为k很小,所以可以每个叶子结点开一个multiset,存这个结点有哪些骑士,同时对线段树每个结点建一个结构体,存当前这一段有哪些骑士,然后儿子更新父亲的时候就用归并排序那样合并就行了,其它没什么要注意的了。代码也不难写。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int Maxn=40010;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
multiset<int>S[Maxn<<1];
int n,m,q,k,F[Maxn],P[Maxn];//F武力值 P居住地
struct A{int Len,b[22];}a[Maxn<<1];
struct Tree{int l,r,lc,rc;}tr[Maxn<<1];
int top[Maxn],tot[Maxn],dep[Maxn],son[Maxn],ys[Maxn],z=0,fa[Maxn];
struct Edge{int y,next;}e[Maxn<<1];
int last[Maxn],len=0;
void ins(int x,int y){int t=++len;e[t].y=y;e[t].next=last[x];last[x]=t;}
void dfs1(int x,int f)
{
    fa[x]=f;dep[x]=dep[f]+1;tot[x]=1;
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(y!=f)
        {
            dfs1(y,x);
            if(tot[y]>tot[son[x]])son[x]=y;
            tot[x]+=tot[y];
        }
    }
}
void dfs2(int x,int Top)
{
    top[x]=Top;ys[x]=++z;
    if(son[x])dfs2(son[x],Top);
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(y!=fa[x]&&y!=son[x])dfs2(y,y);
    }
}
int trlen=0;
void build(int l,int r)
{
    int t=++trlen;
    tr[t].l=l;tr[t].r=r;
    if(l<r)
    {
        int mid=l+r>>1;
        tr[t].lc=trlen+1;build(l,mid);
        tr[t].rc=trlen+1;build(mid+1,r);
    }
}
A merge(A x,A y)//归并 
{
    int l1=1,l2=1;A re;re.Len=0;
    while(l1<=x.Len&&l2<=y.Len&&re.Len<k)
    {
        if(x.b[l1]>y.b[l2])re.b[++re.Len]=x.b[l1++];
        else re.b[++re.Len]=y.b[l2++];
    }
    while(l1<=x.Len&&re.Len<k)re.b[++re.Len]=x.b[l1++];
    while(l2<=y.Len&&re.Len<k)re.b[++re.Len]=y.b[l2++];
    return re;
}
int pos;
void change(int now,int p,int x,int o)
{
    if(tr[now].l==tr[now].r)
    {
        multiset<int>::iterator t;
        if(o==1)S[pos].insert(x);
        else S[pos].erase(S[pos].find(x));
        a[now].Len=0;
        if(!S[pos].empty())
        {
            t=S[pos].end();t--;
            while(a[now].Len<k)
            {
                a[now].b[++a[now].Len]=*t;
                if(t==S[pos].begin())break;
                t--;
            }
        }
        return;
    }
    int lc=tr[now].lc,rc=tr[now].rc,mid=tr[now].l+tr[now].r>>1;
    if(p<=mid)change(lc,p,x,o);else change(rc,p,x,o);
    a[now]=merge(a[lc],a[rc]);
}
A query(int now,int l,int r)
{
    if(tr[now].l==l&&tr[now].r==r)return a[now];
    int lc=tr[now].lc,rc=tr[now].rc,mid=tr[now].l+tr[now].r>>1;
    if(r<=mid)return query(lc,l,r);
    else if(l>mid)return query(rc,l,r);
    else
    {
        A re=merge(query(lc,l,mid),query(rc,mid+1,r));
        return re;
    }
}
void solve(int x,int y)
{
    int tx=top[x],ty=top[y];A ans;ans.Len=0;
    while(tx!=ty)
    {
        if(dep[tx]<dep[ty])swap(tx,ty),swap(x,y);
        ans=merge(ans,query(1,ys[tx],ys[x]));
        x=fa[tx];tx=top[x];
    }
    if(dep[x]>dep[y])swap(x,y);
    ans=merge(ans,query(1,ys[x],ys[y]));
    if(!ans.Len){puts("-1");return;}
    for(int i=1;i<=ans.Len;i++)printf("%d ",ans.b[i]);puts("");
}
int main()
{
    n=read();
    for(int i=1;i<n;i++){int x=read(),y=read();ins(x,y);ins(y,x);}
    dep[0]=0;dfs1(1,0);dfs2(1,1);build(1,z);
    m=read();
    for(int i=1;i<=m;i++)F[i]=read(),P[i]=read();
    q=read();k=read();
    for(int i=1;i<=m;i++)pos=P[i],change(1,ys[P[i]],F[i],1);
    while(q--)
    {
        int op=read(),x=read(),y=read();
        if(op==1)solve(x,y);
        else if(op==2)pos=P[x],change(1,ys[P[x]],F[x],-1),P[x]=y,pos=P[x],change(1,ys[P[x]],F[x],1);
        else pos=P[x],change(1,ys[P[x]],F[x],-1),F[x]=y,pos=P[x],change(1,ys[P[x]],F[x],1);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值