• [HNOI2015]接水果


    题目描述

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

    题解

    这道题的关键就是如何判断路径完全覆盖的情况。

    考虑一条路径u->v,dfn[u]<dfn[v],另一条路径x->y,dfn[x]<dfn[y]xy要覆盖uv需要满足什么条件。

    先考虑lca(u,v)!=u的情况,那么x必须在u的子树里,y必须在v的子树里。

    所以x€dfn[u],dfn[u]+size[u]-1,y€dfn[v],dfn[v]+size[v]-1.

    然后是lca(u,v)==u

    这时下面的点必须要在v的子树内部,上面的点不能在u的子树内部(但可以在u上)。

    前面的东西很好求,但是后面的东西感觉非常复杂,因为它既包括u的子树外的,又包括u的某些其他儿子的子树。

    但我们仔细一想,好像这里的不合法区域是一段连洗的区间。

    我们找出u下面的点v,不合法的区域就是v的子树。

    然后我们把两个点看成一个点的横纵坐标,那么两个点的限制相当于是一个矩形,那么一个询问相当于是从所有覆盖它的矩形中找出权值的第k小。

    整体二分+扫描线+树状数组就好了,这块就比较套路了。

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define N 40009
    using namespace std;
    typedef long long ll;
    const int mod=998244353;
    int tot,deep[N],head[N],p[N][19],dfn[N],top,size[N],tr[N],tott,tottp,n,ans[N],b[N],pp,q;
    inline ll rd(){
        ll x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x;
    }
    struct edge{int n,to;}e[N<<1];
    inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}
    void dfs(int u,int fa){
        dfn[u]=++top;
        size[u]=1;
        for(int i=1;(1<<i)<=deep[u];++i)
          p[u][i]=p[p[u][i-1]][i-1];
        for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
            int v=e[i].to;deep[v]=deep[u]+1;p[v][0]=u;
            dfs(v,u);
            size[u]+=size[v];
        }
    }
    inline int getlca(int a,int b){
        if(deep[a]<deep[b])swap(a,b);
        for(int i=18;i>=0;--i)if(deep[a]-(1<<i)>=deep[b])a=p[a][i];
        if(a==b)return a;
        for(int i=18;i>=0;--i)if(p[a][i]!=p[b][i])a=p[a][i],b=p[b][i];
        return p[a][0];
    }
    inline void upd(int x,int y){while(x<=(n+5))tr[x]+=y,x+=x&-x;}
    inline int query(int x){int ans=0;while(x)ans+=tr[x],x-=x&-x;return ans;}
    struct matrix{
        int x,yf,ys,tag;ll num;    
        int id;
    }m[N*5],m1[N*5],m2[N*5];
    inline bool cmptim(matrix a,matrix b){
        if(a.x!=b.x)return a.x<b.x;
        else return a.tag>b.tag;
    }
    void upd2(int x,int y,int num){
        upd(x,num);upd(y+1,-num);
    }
    void solve(int l,int r,int L,int R){
        if(L==R){
            for(int i=l;i<=r;++i)if(m[i].id)ans[m[i].id]=L;
            return;
        }
        int mid=(L+R)>>1;
        int p1=0,p2=0;
        for(int i=l;i<=r;++i){
            if(m[i].id){
                int xx=query(m[i].yf);
                if(xx>=m[i].num)m1[++p1]=m[i];
                else m[i].num-=xx,m2[++p2]=m[i];
            }
            else{
                if(m[i].num<=b[mid])upd2(m[i].yf,m[i].ys,m[i].tag),m1[++p1]=m[i];
                else m2[++p2]=m[i];
            }
        }
        for(int i=1;i<=p1;++i){
          if(!m1[i].id)upd2(m1[i].yf,m1[i].ys,-m1[i].tag);
          m[l+i-1]=m1[i];
        }
        for(int i=1;i<=p2;++i)m[l+p1+i-1]=m2[i];
        solve(l,l+p1-1,L,mid);solve(l+p1,r,mid+1,R);
    }
    inline int jump(int x,int dep){
        for(int i=18;i>=0;--i)if((1<<i)&dep)x=p[x][i];
        return x;
    }
    int main(){
        n=rd();pp=rd();q=rd();int u,v,w;
        for(int i=1;i<n;++i){
            u=rd();v=rd();
            add(u,v);add(v,u);
        }
        dfs(1,0);
        for(int i=1;i<=pp;++i){
            u=rd();v=rd();w=rd();b[++tottp]=w;
            if(dfn[u]>dfn[v])swap(u,v);
            int lca=getlca(u,v);
            if(lca==u){
                int x=jump(v,deep[v]-deep[u]-1);
                m[++tott]=matrix{1,dfn[v],dfn[v]+size[v]-1,1,w,0};
                m[++tott]=matrix{dfn[x],dfn[v],dfn[v]+size[v]-1,-1,w,0};
                m[++tott]=matrix{dfn[v],dfn[x]+size[x],n,1,w,0};
                m[++tott]=matrix{dfn[v]+size[v],dfn[x]+size[x],n,-1,w,0};
            } 
            else{
                m[++tott]=matrix{dfn[u],dfn[v],dfn[v]+size[v]-1,1,w,0};
                m[++tott]=matrix{dfn[u]+size[u],dfn[v],dfn[v]+size[v]-1,-1,w,0};
            }
        }
        sort(b+1,b+tottp+1);tottp=unique(b+1,b+tottp+1)-b-1;
        for(int i=1;i<=q;++i){
            m[++tott].x=rd();m[tott].yf=rd();m[tott].num=rd();m[tott].id=i;m[tott].tag=-2;
            m[tott].x=dfn[m[tott].x];m[tott].yf=dfn[m[tott].yf]; 
            if(m[tott].x>m[tott].yf)swap(m[tott].x,m[tott].yf);
        }
        sort(m+1,m+tott+1,cmptim);
        solve(1,tott,1,tottp);
        for(int i=1;i<=q;++i)printf("%d
    ",b[ans[i]]);
        return 0;
    }
  • 相关阅读:
    PHP array_intersect_uassoc
    PHP array_intersect_key
    PHP array_intersect_assoc
    PHP array_flip
    PHP array_filter
    PHP array_fill
    PHP array_fill_keys
    Android4.0-Fragment框架实现方式剖析
    Fragment 生命周期
    WebView
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10287006.html
Copyright © 2020-2023  润新知