BZOJ4009 接水果

Link

Difficulty

算法难度6,思维难度7,代码难度7

Description

给你一棵树,给你若干个盘子,每个盘子对应着一条链和一个权值

会掉下来若干个苹果,每个苹果对应着一条链和一个k

盘子可以接苹果当且仅当盘子的路径是苹果的路径的子路径

苹果会选择可以接住它的盘子中的权值第k小的

求每个苹果被哪个盘子接住,输出权值

1 ≤ n , m , q ≤ 4 ∗ 1 0 4 1\le n,m,q\le 4*10^4 1n,m,q4104

Solution

首先权值离散化

然后我们来讨论可以接住苹果的盘子满足什么性质

假设苹果的路径为 ( x , y ) (x,y) (x,y),盘子的路径为 ( x ′ , y ′ ) (x',y') (x,y)

(以下我们记 d f n ( x ) , e d ( x ) dfn(x),ed(x) dfn(x),ed(x)分别为 x x x d f s dfs dfs序和子树内最后一个点的 d f s dfs dfs序)

  1. l c a ( x ′ , y ′ ) ≠ x ′ lca(x',y')\ne x' lca(x,y)̸=x y ′ y' y

    那么我们发现 x , y x,y x,y只能分别位于 x ′ , y ′ x',y' x,y的子树内

    即: d f n ( x ′ ) ≤ d f n ( x ) ≤ e d ( x ′ ) , d f n ( y ′ ) ≤ d f n ( y ) ≤ e d ( y ′ ) dfn(x')\le dfn(x)\le ed(x'),dfn(y')\le dfn(y)\le ed(y') dfn(x)dfn(x)ed(x),dfn(y)dfn(y)ed(y)

    或: d f n ( x ′ ) ≤ d f n ( y ) ≤ e d ( x ′ ) , d f n ( y ′ ) ≤ d f n ( x ) ≤ e d ( y ′ ) dfn(x')\le dfn(y)\le ed(x'),dfn(y')\le dfn(x)\le ed(y') dfn(x)dfn(y)ed(x),dfn(y)dfn(x)ed(y)

    这时你就会发现盘子的限制条件可以分成两个矩形

  2. l c a ( x ′ , y ′ ) = x ′ lca(x',y')=x' lca(x,y)=x(另一种也一样)

    那我们记 ( x ′ , y ′ ) (x',y') (x,y)上最靠近 x ′ x' x的那个点为 z z z的话(也就是深度第二小的点)

    那么我们发现 x , y x,y x,y只能一个位于 y ′ y' y的子树内,另一个在 z z z的子树之外

    即: d f n ( y ′ ) ≤ d f n ( x ) ≤ e d ( y ′ ) , 1 ≤ d f n ( y ) &lt; d f n ( z ) dfn(y&#x27;)\le dfn(x) \le ed(y&#x27;),1\le dfn(y)&lt;dfn(z) dfn(y)dfn(x)ed(y),1dfn(y)<dfn(z) e d ( z ) &lt; d f n ( y ) ≤ n ed(z)&lt;dfn(y) \le n ed(z)<dfn(y)n

    或: d f n ( y ′ ) ≤ d f n ( y ) ≤ e d ( y ′ ) , 1 ≤ d f n ( x ) &lt; d f n ( z ) dfn(y&#x27;)\le dfn(y) \le ed(y&#x27;),1\le dfn(x)&lt;dfn(z) dfn(y)dfn(y)ed(y),1dfn(x)<dfn(z) e d ( z ) &lt; d f n ( x ) ≤ n ed(z)&lt;dfn(x) \le n ed(z)<dfn(x)n

    这时你会发现这东西和上面的差不多,只不过这个是四个矩形而已

这时问题就转换成了给定一堆矩形,还有一堆点,矩形带权,对于每个点求包含它的矩形中第k小的权值

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<vector>
#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,tot,H,Hash[N];
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 dfn[N],dfn_clock,ed[N],dep[N],st[16][N];
inline void dfs(int x,int fa){
    dfn[x]=++dfn_clock;
    dep[x]=dep[fa]+1;
    st[0][x]=fa;
    for(int i=1;i<=15;++i)st[i][x]=st[i-1][st[i-1][x]];
    for(int i=head[x];i;i=Next[i]){
        int u=to[i];
        if(u==fa)continue;
        dfs(u,x);
    }
    ed[x]=dfn_clock;
}
inline int getlca(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    for(int i=15;i>=0;--i)
        if(dep[st[i][x]]>=dep[y])
            x=st[i][x];
    if(x==y)return x;
    for(int i=15;i>=0;--i)
        if(st[i][x]!=st[i][y])
            x=st[i][x],y=st[i][y];
    return st[0][x];
}
inline int jump(int x,int y){
    for(int i=15;i>=0;--i)
        if(dep[st[i][x]]>dep[y])
            x=st[i][x];
    return x;
}
struct data{
    int x,y1,y2,val,id,type;
    data(){}
    data(int _x,int _y1,int _y2,int _val,int _id,int _type):
        x(_x),y1(_y1),y2(_y2),val(_val),id(_id),type(_type){}
    inline bool operator < (const data& b) const {
        if(x==b.x)return type<b.type;
        else return x<b.x;
    }
};
vector<data> t;
int a[N];
inline void modify(int x,int v){
    while(x<=n){
        a[x]+=v;
        x+=x&-x;
    }
}
inline int query(int x){
    int ans=0;
    while(x){
        ans+=a[x];
        x-=x&-x;
    }
    return ans;
}
int ans[N];
inline void solve(vector<data> &t,int l,int r){
    if(l==r){
        for(vector<data>::iterator it=t.begin();it!=t.end();++it){
            if((*it).type==2)
                ans[(*it).id]=Hash[l];
        }
        return;
    }
    int mid=(l+r)>>1;
    vector<data> ls,rs;
    for(vector<data>::iterator it=t.begin();it!=t.end();++it){
        data d=*it;
        if(d.type==2){
            int num=query(d.y1);
            if(d.val<=num)ls.push_back(d);
            else{
                d.val-=num;
                rs.push_back(d);
            }
        }
        else{
            if(d.val<=mid)ls.push_back(d);
            else rs.push_back(d);
            if(d.val>mid)continue;
            modify(d.y1,d.id);
            modify(d.y2+1,-d.id);
        }
    }
    solve(ls,l,mid);
    solve(rs,mid+1,r);
}
int main(){
    n=read();m=read();q=read();
    for(int i=1;i<n;++i){
        int x=read(),y=read();
        addedge(x,y);addedge(y,x);
    }
    dfs(1,0);
    for(int i=1;i<=m;++i){
        int x=read(),y=read(),c=read();
        int lca=getlca(x,y);
        Hash[++H]=c;
        if(lca!=x && lca!=y){
            t.push_back(data(dfn[x],dfn[y],ed[y],c,1,1));
            t.push_back(data(ed[x],dfn[y],ed[y],c,-1,3));
            t.push_back(data(dfn[y],dfn[x],ed[x],c,1,1));
            t.push_back(data(ed[y],dfn[x],ed[x],c,-1,3));
        }
        else{
            if(lca==y)swap(x,y);
            int z=jump(y,x);
            t.push_back(data(1,dfn[y],ed[y],c,1,1));
            t.push_back(data(dfn[z]-1,dfn[y],ed[y],c,-1,3));
            t.push_back(data(ed[z]+1,dfn[y],ed[y],c,1,1));
            t.push_back(data(n,dfn[y],ed[y],c,-1,3));
            t.push_back(data(dfn[y],1,dfn[z]-1,c,1,1));
            t.push_back(data(dfn[y],ed[z]+1,n,c,1,1));
            t.push_back(data(ed[y],1,dfn[z]-1,c,-1,3));
            t.push_back(data(ed[y],ed[z]+1,n,c,-1,3));
        }
    }
    for(int i=1;i<=q;++i){
        int x=read(),y=read(),c=read();
        t.push_back(data(dfn[x],dfn[y],-1,c,i,2));
    }
    sort(Hash+1,Hash+H+1);
    H=unique(Hash+1,Hash+H+1)-Hash-1;
    for(vector<data>::iterator it=t.begin();it!=t.end();++it){
        if((*it).type!=2)
            (*it).val=lower_bound(Hash+1,Hash+H+1,(*it).val)-Hash;
    }
    sort(t.begin(),t.end());
    solve(t,1,H);
    for(int i=1;i<=q;++i)printf("%d\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值