[HNOI2015]接水果

Description
风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果。由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更加难的版本。首先有一个地图,是一棵由 n 个顶点、n-1 条边组成的树(例如图 1给出的树包含 8 个顶点、7 条边)。这颗树上有 P 个盘子,每个盘子实际上是一条路径(例如图 1 中顶点 6 到顶点 8 的路径),并且每个盘子还有一个权值。第 i 个盘子就是顶点a_i到顶点b_i的路径(由于是树,所以从a_i到b_i的路径是唯一的),权值为c_i。接下来依次会有Q个水果掉下来,每个水果本质上也是一条路径,第i 个水果是从顶点 u_i 到顶点v_i 的路径。幽香每次需要选择一个盘子去接当前的水果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径(例如图1中从 3到7 的路径是从1到8的路径的子路径)。这里规定:从a 到b的路径与从b到 a的路径是同一条路径。当然为了提高难度,对于第 i 个水果,你需要选择能接住它的所有盘子中,权值第 k_i 小的那个盘子,每个盘子可重复使用(没有使用次数的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗?
aaaa.PNG

Input
第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数。

接下来n-1 行,每行两个数 a、b,表示树上的a和b 之间有一条边。树中顶点
按1到 n标号。 接下来 P 行,每行三个数 a、b、c,表示路径为 a 到 b、权值为 c 的盘子,其
中0≤c≤10^9,a不等于b。
接下来Q行,每行三个数 u、v、k,表示路径为 u到 v的水果,其中 u不等于v,你需要选择第 k小的盘子,
第k 小一定存在。

Output
对于每个果子,输出一行表示选择的盘子的权值。

Sample Input
10 10 10
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
3 2 217394434
10 7 13022269
6 7 283254485
6 8 333042360
4 6 442139372
8 3 225045590
10 4 922205209
10 8 808296330
9 2 486331361
4 9 551176338
1 8 5
3 8 3
3 8 4
1 8 3
4 8 1
2 3 1
2 3 1
2 3 1
2 4 1
1 4 1

Sample Output
442139372
333042360
442139372
283254485
283254485
217394434
217394434
217394434
217394434
217394434

HINT
N,P,Q<=40000。


考虑一下题型的转化

我们可以把每个水果路径端点的dfs序提出来,将其变成一个平面内的点

然后我们考虑一个盘子(u,v)能够接到哪些水果(l,r)(我们这里令dfn[u]<dfn[v],dfn[l]<dfn[r])

如果lca为u,那么这个盘子能接到的水果的l,r需要满足

\(\begin{cases}1&\leqslant l'<x'\\v'&\leqslant r'<v'+size[v]\end{cases}\)\(\begin{cases}x'+size[x]&<l'\leqslant n\\v'&\leqslant r'<v'+size[v]\end{cases}\)

其中,l',r'等表示dfn[l],dfn[r]...,size[v]表示以v为根的子树大小,x为v到u路径上,u的儿子节点

如果lca不为u,那么这个盘子能接到的水果的l,r需要满足

\[\begin{cases}u'\leqslant l'<u'+size[u]\\v'\leqslant r'<v'+size[v]\end{cases}\]

这样的话我们可以发现,每个盘子都可以表示成平面内的一个矩阵,如果有某个点在其覆盖范围内,就说明这个点,也就是这个点表示的水果能被这个矩阵表示的盘子接到

于是问题转化为了给定平面内一些点和一些带权值的矩阵,对于每个点求出覆盖其的矩阵权值的第k小

这样的话我们可以使用整体二分,当然也可以使用树套树,这里我采用后面一种写法

我们将平面中x轴排序,使用扫描线,如果使用Lazy标记的话,空间肯定开不下,因此我们采用标记永久化。

我们使用权值线段树套位置线段树,反过来的话求第\(k\)大较为麻烦

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Fi first
#define Se second
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
    int x=0,f=1;char ch=gc();
    for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x<0)    putchar('-'),x=-x;
    if (x>9)    print(x/10);
    putchar(x%10+'0');
}
const int N=4e4,M=2e7;
int list[N+10],dfn[N+10],Ans[N+10];
int n,P,Q;
struct S1{
    int pre[(N<<1)+10],now[N+10],child[(N<<1)+10],tot,Time;
    int fa[N+10],deep[N+10],top[N+10],Rem[N+10],size[N+10];
    void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
    void insert(int x,int y){join(x,y),join(y,x);}
    void dfs(int x){
        deep[x]=deep[fa[x]]+1,size[x]=1;
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa[x]) continue;
            fa[son]=x,dfs(son);
            size[x]+=size[son];
            if (size[Rem[x]]<size[son]) Rem[x]=son;
        }
    }
    void build(int x){
        if (!x) return;
        dfn[x]=++Time;
        top[x]=Rem[fa[x]]==x?top[fa[x]]:x;
        build(Rem[x]);
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa[x]||son==Rem[x])    continue;
            build(son);
        }
    }
    pair<int,int> Lca(int x,int y){
        int Last=0;
        while (top[x]!=top[y]){
            if (deep[top[x]]<deep[top[y]])  swap(x,y);
            Last=top[x],x=fa[top[x]];
        }
        if (x==y)   return make_pair(x,Last);
        if (deep[x]>deep[y])    swap(x,y);
        return make_pair(x,Rem[x]);
    }
}HLD;//Heavy Light Decomposition
struct S2{
    int root[(N<<2)+10];
    struct S3{
        int ls[M+10],rs[M+10],cnt[M+10],tot;
        void Modify(int &p,int l,int r,int x,int y,int type){
            if (!p) p=++tot;
            if (x<=l&&r<=y){
                cnt[p]+=type;
                return;
            }
            int mid=(l+r)>>1;
            if (x<=mid) Modify(ls[p],l,mid,x,y,type);
            if (y>mid)  Modify(rs[p],mid+1,r,x,y,type);
        }
        int Query(int p,int l,int r,int x){
            if (l==r)   return cnt[p];
            int mid=(l+r)>>1;
            if (x<=mid) return Query(ls[p],l,mid,x)+cnt[p];
            else    return Query(rs[p],mid+1,r,x)+cnt[p];
        }
    }PST;//Position Segment Tree
    #define ls (p<<1)
    #define rs (p<<1|1)
    void Modify(int p,int l,int r,int v,int x,int y,int type){
        PST.Modify(root[p],1,n,x,y,type);
        if (l==r)   return;
        int mid=(l+r)>>1;
        if (v<=mid) Modify(ls,l,mid,v,x,y,type);
        else    Modify(rs,mid+1,r,v,x,y,type);
    }
    int Query(int p,int l,int r,int k,int x){
        if (l==r)   return list[l];
        int mid=(l+r)>>1,res=PST.Query(root[ls],1,n,x);
        if (k<=res) return Query(ls,l,mid,k,x);
        else    return Query(rs,mid+1,r,k-res,x);
    }
    #undef ls
    #undef rs
}PST_VST;//Position Segment Tree in Value Segment Tree
struct S4{
    int x,l,r,k,type;
    void insert(int _x,int _l,int _r,int _k,int _type){x=_x,l=_l,r=_r,k=_k,type=_type;}
    bool operator <(const S4 &tis)const{return x<tis.x;}
}plate[(N<<3)+10];
struct S5{
    int x,y,k,ID;
    void insert(int _x,int _y,int _k,int _ID){x=_x,y=_y,k=_k,ID=_ID;}
    bool operator <(const S5 &tis)const{return x<tis.x;}
}fruit[N+10];
int cnt;
void insert(int L,int R,int l,int r,int k){
    plate[++cnt].insert(L,l,r,k,1);
    plate[++cnt].insert(R+1,l,r,k,-1);
}
void Ins(int L,int R,int l,int r,int k){
    if (L>R)    return;
    insert(L,R,l,r,k);
    insert(l,r,L,R,k);
}
int main(){
    n=read(),P=read(),Q=read();
    for (int i=1;i<n;i++){
        int x=read(),y=read();
        HLD.insert(x,y);
    }
    HLD.dfs(1),HLD.build(1);
    for (int i=1;i<=P;i++){
        int x=read(),y=read(),k=read();
        pair<int,int>tmp=HLD.Lca(x,y);
        if (dfn[x]>dfn[y])  swap(x,y);
        if (tmp.Fi==x){
            Ins(1,dfn[tmp.Se]-1,dfn[y],dfn[y]+HLD.size[y]-1,k);
            Ins(dfn[tmp.Se]+HLD.size[tmp.Se],n,dfn[y],dfn[y]+HLD.size[y]-1,k);
        }else   Ins(dfn[x],dfn[x]+HLD.size[x]-1,dfn[y],dfn[y]+HLD.size[y]-1,k);
        list[i]=k;
    }
    sort(list+1,list+1+P);
    int T=unique(list+1,list+1+P)-list-1;
    for (int i=1;i<=cnt;i++)    plate[i].k=lower_bound(list+1,list+1+T,plate[i].k)-list;
    for (int i=1;i<=Q;i++){
        int x=read(),y=read(),k=read();
        if (dfn[x]>dfn[y])  swap(x,y);
        fruit[i].insert(dfn[x],dfn[y],k,i);
    }
    sort(fruit+1,fruit+1+Q);
    sort(plate+1,plate+1+cnt);
    for (int i=1,j=1;i<=Q;i++){
        while (j<=cnt&&plate[j].x<=fruit[i].x)  PST_VST.Modify(1,1,n,plate[j].k,plate[j].l,plate[j].r,plate[j].type),j++;
        Ans[fruit[i].ID]=PST_VST.Query(1,1,n,fruit[i].k,fruit[i].y);
    }
    for (int i=1;i<=Q;i++)  printf("%d\n",Ans[i]);
    return 0;
}

转载于:https://www.cnblogs.com/Wolfycz/p/10000261.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值