zoukankan      html  css  js  c++  java
  • 接水果(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
    ",dy[ans[i]]);
        }
        return 0;
    }
    View Code
     
  • 相关阅读:
    python 修改excel
    python 正则表达式规则收集
    anusplina 4.36版本使用提示 说明
    python 汉字编码问题
    python IOError: [Errno 22] invalid mode ('r') or filename:
    将矩阵数据转换为栅格图 filled.contour()
    将数值矩阵映射为栅格图
    一脚踩进java之基础篇23——常用API(Object、String)
    一脚踩进java之基础篇22——面向对象 (不同修饰符使用细节)
    一脚踩进java之基础篇21——面向对象 (访问修饰符、代码块)
  • 原文地址:https://www.cnblogs.com/liankewei/p/10657099.html
Copyright © 2011-2022 走看看