接水果(fruit)

接水果(fruit)

风见幽香非常喜欢玩一个叫做 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$ 小的那个盘子,每个盘子可重复使用(没有使用次数的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗?
 

 solution
这题真的奇怪:盘子比水果小才接的到,,,
考虑一个盘子,他的两端u,v
如果一个一个水果的两端在u,v的子树以内,那么他就是可以被接到的
求出dfs序,把这个水果的两个端点映射到平面上,就变成点要在矩形内的限制。
于是问题转化为求覆盖一个点的第k大矩形。
限制有3维,考虑整体二分。
先按x排序,y用扫描线,把权值拿去整体二分。
具体实现:
当前二分权值v,加入<=mid的所有矩形,查询每个点覆盖他的矩形有几个。
如果大于限制就扔l-mid,否则扔mid=1-r,并且把限制减去当前答案。
 
盘子对应矩形是分下类:
u v不互为祖先就是直接的两段连续dfs序
假设深度较大的子树是u,深度较小的子树是v。v这条链上的儿子是k
u 仍是dfs序,并上k在整棵树的补集。
 
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define maxn 320005
using namespace std;
int n,P,Q,head[maxn],tot,sc,dft[maxn],dfn[maxn];
int deep[maxn],f[maxn][22],top,Max,q[maxn],ans[maxn];
int tr[maxn],tx[maxn],tp,cnt,dy[maxn];
map<int,int>ls;
struct node{
    int v,nex;
}e[maxn*2];
struct sq{
    int fl,pl,a,b,v,val;
}a[maxn],b[maxn];
void lj(int t1,int t2){
    e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
}
void dfs(int k,int fa){
    dft[k]=++sc;deep[k]=deep[fa]+1;f[k][0]=fa;
    for(int i=head[k];i;i=e[i].nex){
        if(e[i].v!=fa)dfs(e[i].v,k);
    }
    dfn[k]=sc;
}
int Lca(int u,int v){
    if(deep[u]<deep[v])swap(u,v);
    for(int x=20;x>=0;x--)if(deep[f[u][x]]>=deep[v])u=f[u][x];
    for(int x=20;x>=0;x--)if(f[u][x]!=f[u][x])u=f[u][x],v=f[v][x];
    return u==v?u:f[u][0];
}
bool cmp(sq a,sq b){
    return a.pl<b.pl||(a.pl==b.pl&&a.fl<b.fl);
}
void add(int i,int v){
    for(;i<=n;i+=i&-i)tr[i]+=v;
}
int ask(int i){
    int sum=0;
    for(;i;i-=i&-i)sum+=tr[i];
    return sum;
}
void add(int xa,int xb,int ya,int yb,int w){
    if(xa>xb||ya>yb||ya<0||xa<0)return;
    a[++top]=(sq){0,xa,ya,yb,w,1};
    a[++top]=(sq){0,xb+1,ya,yb,w,-1};
}
void lsh(){
    sort(tx+1,tx+tp+1);
    cnt=0;
    for(int i=1;i<=tp;i++)
        if(!ls[tx[i]])ls[tx[i]]=++cnt,dy[cnt]=tx[i];
}
void solve(int l,int r,int ql,int qr){
    if(ql>qr)return;
    if(l==r){
        for(int i=ql;i<=qr;i++){
            if(a[i].fl>0)ans[a[i].fl]=l;
        }
        return;
    }
    int mid=l+r>>1;
    for(int i=ql;i<=qr;i++){
        if(a[i].fl>0){
            q[i]=ask(a[i].a);
        }
        else {
            if(a[i].v<=mid){
                add(a[i].a,a[i].val);add(a[i].b+1,-a[i].val);
            }
        }
    }
    for(int i=ql;i<=qr;i++){
        if(a[i].fl==0){
            if(a[i].v<=mid){
                add(a[i].a,-a[i].val);add(a[i].b+1,a[i].val);
            }
        }
    }
    int t=ql-1;
    for(int i=ql;i<=qr;i++){
        if(a[i].fl>0){
            if(q[i]>=a[i].v)b[++t]=a[i];
        }
        else {
            if(a[i].v<=mid)b[++t]=a[i];
        }
    }
    int ff=t;
    for(int i=ql;i<=qr;i++){
        if(a[i].fl>0){
            if(q[i]<a[i].v){
                a[i].v-=q[i];
                b[++t]=a[i];
            }
        }
        else {
            if(a[i].v>mid)b[++t]=a[i];
        }
    }
    for(int i=ql;i<=qr;i++)a[i]=b[i];
    solve(l,mid,ql,ff);solve(mid+1,r,ff+1,qr);
}
int main()
{
    cin>>n>>P>>Q;
    for(int i=1,t1,t2;i<n;i++){
        scanf("%d%d",&t1,&t2);
        lj(t1,t2);lj(t2,t1);
    }
    dfs(1,0);
    for(int j=1;j<=20;j++)
    for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
    for(int i=1,u,v,w;i<=P;i++){
        scanf("%d%d%d",&u,&v,&w);
        tx[++tp]=w;
        if(deep[u]<deep[v])swap(u,v);
        int lca=Lca(u,v);
        if(lca==v){
            int dep=deep[u]-deep[v]-1;
            int t=u;
            for(int x=20;x>=0;x--){
                if((1<<x)<=dep){
                    t=f[t][x];dep-=(1<<x);
                }
            }
            add(dft[u],dfn[u],1,dft[t]-1,w);
            add(1,dft[t]-1,dft[u],dfn[u],w);
            
            add(dft[u],dfn[u],dfn[t]+1,n,w);
            add(dfn[t]+1,dft[u],dfn[u],n,w);
        }
        else {
            add(dft[u],dfn[u],dft[v],dfn[v],w);
            add(dft[v],dfn[v],dft[u],dfn[u],w);
        }
    }
    lsh();
    for(int i=1,t1,t2,t3;i<=Q;i++){
        scanf("%d%d%d",&t1,&t2,&t3);
        a[++top].fl=i;
        a[top].pl=dft[t2];a[top].a=dft[t1];a[top].v=t3;
    }
    sort(a+1,a+top+1,cmp);
    for(int i=1;i<=top;i++){
        if(!a[i].fl)a[i].v=ls[a[i].v];
    }
    solve(1,cnt,1,top);
    for(int i=1;i<=Q;i++){
        printf("%d\n",dy[ans[i]]);
    }
    return 0;
}
View Code

 

 
posted @ 2019-04-04 21:11  liankewei123456  阅读(787)  评论(0编辑  收藏  举报