bzoj4336: BJOI2015 骑士的旅行

Description

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

Input

第一行,一个整数N,表示有N座城,编号为1~N。
接下来N-1行,每行两个整数Ui和Vi,表示城Ui和城Vi之间有一条道路相连。
第N+1行,一个整数M,表示有M个骑士。
接下来M行,每行两个整数Fi和Pi。按顺序依次表示编号为1~M的每名骑士的武
力值和居住地。
第N+M+2行,两个整数Q,K,分别表示操作次数和每次旅行挑战的骑士数目上限。
接下来Q行,每行三个整数Ti,Xi,Yi。Ti取值范围为{1,2,3},表示操作类型。
一共有以下三种类型的操作:
Ti=1时表示一次旅行,Henry将从城Xi出发前往城市Yi;
Ti=2时表示编号为Xi的骑士的居住地搬到城Yi;
Ti=3时表示编号为Xi的骑士的武力值修正为Yi。

Output

输出若干行,依次为每个旅行的答案。
对每个Ti=1的询问,输出一行,按从大到小的顺序输出Henry在这次旅行中挑战的
所有骑士的武力值。如果路线上没有骑士,输出一行,为一个整数-1。
对每个点用multiset维护点权,树链剖分+线段树维护区间上前k大的数(降序),对于查询可以把对应的区间提取出来用堆维护一下多路归并求出前k大
单次查询时间复杂度约为O((log^2(n)+k)log(log^2(n))),修改为O(klogn)
#include<bits/stdc++.h>
const int N=40007;
char buf[N*100],*ptr=buf-1;
int _(){
    int x=0,c=*++ptr;
    while(c<48)c=*++ptr;
    while(c>47)x=x*10+c-48,c=*++ptr;
    return x;
}
int n,m,q,k;
int es[N*2],enx[N*2],e0[N],ep=2;
std::multiset<int,std::greater<int> >vs[N];
int as[N],bs[N];
int fa[N],sz[N],son[N],dep[N],top[N],id[N],idr[N],idp=0;
int _l,_r,*Q[N],qp;
bool cmp(int*a,int*b){
    return *a<*b;
}
void push(int*a){
    Q[qp++]=a;
    std::push_heap(Q,Q+qp,cmp);
}
struct node{
    node*lc,*rc,*f;
    int L,R;
    int v[21];
    void init(int x){
        int p=0;
        for(std::multiset<int>::iterator it=vs[x].begin();p<k&&it!=vs[x].end();v[p++]=*(it++));
        for(;p<k;v[p++]=-1);
    }
    void up(){
        int p=0,p1=0,p2=0,*v1=lc->v,*v2=rc->v;
        while(p<k&&p1<k&&p2<k)v[p++]=v1[p1]>v2[p2]?v1[p1++]:v2[p2++];
        while(p<k&&p1<k)v[p++]=v1[p1++];
        while(p<k&&p2<k)v[p++]=v2[p2++];
    }
    void upds(){
        for(node*w=f;w;w->up(),w=w->f);
    }
    void get(){
        if(_l<=L&&R<=_r){
            if(~v[0])push(v);
            return;
        }
        int M=L+R>>1;
        if(_l<=M)lc->get();
        if(_r>M)rc->get();
    }
}ns[N*2],*np=ns,*rt[N],*pos[N];
node*build(int L,int R){
    node*w=np++;
    w->L=L;w->R=R;
    memset(w->v,-1,sizeof(w->v));
    if(L!=R){
        int M=L+R>>1;
        (w->lc=build(L,M))->f=
        (w->rc=build(M+1,R))->f=w;
        w->up();
    }else{
        pos[idr[L]]=w;
        w->init(idr[L]);
    }
    return w;
}
void f1(int w,int pa){
    dep[w]=dep[fa[w]=pa]+1;
    sz[w]=1;
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u!=pa){
            f1(u,w);
            sz[w]+=sz[u];
            if(sz[u]>sz[son[w]])son[w]=u;
        }
    }
}
void f2(int w,int tp){
    top[w]=tp;
    idr[id[w]=++idp]=w;
    if(son[w])f2(son[w],tp);
    else rt[tp]=build(id[tp],id[w]);
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u!=fa[w]&&u!=son[w])f2(u,u);
    }
}
int main(){
    buf[fread(buf,1,sizeof(buf),stdin)]=0;
    n=_();
    for(int i=1,a,b;i<n;++i){
        a=_();b=_();
        es[ep]=b;enx[ep]=e0[a];e0[a]=ep++;
        es[ep]=a;enx[ep]=e0[b];e0[b]=ep++;
    }
    m=_();
    for(int i=1;i<=m;++i){
        as[i]=_();bs[i]=_();
        vs[bs[i]].insert(as[i]);
    }
    q=_();k=_();
    f1(1,0);f2(1,1);
    for(int i=0,o,x,y;i<q;++i){
        o=_();x=_();y=_();
        if(o==1){
            qp=0;
            int a=top[x],b=top[y];
            while(a!=b){
                if(dep[a]<dep[b])std::swap(x,y),std::swap(a,b);
                _l=id[a],_r=id[x],rt[a]->get();
                x=fa[a];a=top[x];
            }
            if(dep[x]>dep[y])std::swap(x,y);
            _l=id[x],_r=id[y],rt[top[x]]->get();
            if(!qp)printf("-1");
            for(int j=0;j<k&&qp;++j){
                int*p=Q[0];
                std::pop_heap(Q,Q+qp--,cmp);
                printf("%d ",*p);
                if(~*++p)push(p);
            }
            putchar(10);
        }else if(o==2){
            vs[bs[x]].erase(vs[bs[x]].find(as[x]));
            pos[bs[x]]->init(bs[x]);
            pos[bs[x]]->upds();
            vs[bs[x]=y].insert(as[x]);
            pos[bs[x]]->init(bs[x]);
            pos[bs[x]]->upds();
        }else{
            vs[bs[x]].erase(vs[bs[x]].find(as[x]));
            vs[bs[x]].insert(as[x]=y);
            pos[bs[x]]->init(bs[x]);
            pos[bs[x]]->upds();
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ccz181078/p/6417710.html