[HNOI2015]接水果

题意

给你一个树上路径集合 S, S , 每条路径有个权值

每次询问一条路径 p:xy, p : x → y , 问他在 S S 中包含的路径中权值第k小的是多少


题解

先考虑怎么判断一条路径是否被另一条路径包含

先求出这棵树的 dfs d f s , , Lu=dfnu,Ru=dfnu+szu1

考虑把一条路径 uv u → v 投影成二维平面上的点 (Lu,Lv),Lu<Lv ( L u , L v ) , L u < L v

. . 如果是在链上

那么包含uv的路径 xy x → y 要满足 1LxLu,LvLyRv 1 ≤ L x ≤ L u , L v ≤ L y ≤ R v

也就是要求点 (Lx,Ly) ( L x , L y ) 在矩形 {(1,Lv),(Lu,Rv)} { ( 1 , L v ) , ( L u , R v ) }

所以

一条路径包含多少条路径 对应点被多少个矩形覆盖

后者可以按照 x x 排序扫描线然后维护y坐标的前缀和求出

. . 考虑在树上

1.如果 lca(u,v)u l c a ( u , v ) ≠ u

那么就要求路径 p p 满足x u u 的子树里,y v v 的子树里

也就是LuLxRu,LvLyRv

(Lx,Ly) ( L x , L y ) 在矩形 {(Lu,Lv),(Ru,Rv)} { ( L u , L v ) , ( R u , R v ) }

2. 2. 如果 lca(u,v)=u l c a ( u , v ) = u

z z uv上的第一个点

那么就要求路径 p p 满足一个节点在v子树内 , , 一个节点在z子树外

也就是 (Lx,Ly) ( L x , L y ) 在矩形 {(1,Lv),(Lz1,Rv)}{(Lv,Rz+1),(Rv,n)} { ( 1 , L v ) , ( L z − 1 , R v ) } ∪ { ( L v , R z + 1 ) , ( R v , n ) }

考虑怎么求解

如果只有一个询问我们可以二分一个答案

然后加入权值小于这个答案的路径对应的矩形 , , 然后判断(Lx,Ly)被覆盖了多少次

如果询问很多我们就可以用整体二分

考虑怎么卡常

1.lca(u,v)=uLv[Lu,Ru] 1. l c a ( u , v ) = u ⇔ L v ∈ [ L u , R u ]

2. 2. 找路径上第一个点可以用树剖 , , 比倍增快很多

3.维护 y y 坐标前缀和用树状数组即可

4.二分答案的区间应该是 [1,P] [ 1 , P ] 而不是 [1,] [ 1 , ∞ ]

5. 5. 不要存矩形 , , 直接存扫描线

6.先在外面把点和扫描线按照 x x 排序然后在整体二分里面只要twopointer扫一下

7.twopointer 7. t w o − p o i n t e r 时以点的 x x 坐标为基准会好写一些

8.整体二分中传下去的操作也要满足 x x 升序这样就不要每次排序了

9.用指针也许会快一些

非指针版

#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
    char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
    while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
template<class T>inline void we(T x){
    if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=2e5+5,inf=1e9;
typedef int arr[N];
struct eg{int nx,to;}e[N];
struct Line{
    int x,L,R,w,val;
    inline bool operator<(const Line b)const{return x<b.x;}
}p[N],tp[N];
struct qry{
    int x,y,k,id;
    inline bool operator<(const qry b)const{return x<b.x;}
}q[N],tq[N];
int n,m,Q,dft;arr c,h,fa,fi,sz,Lx,Rx,dep,son,top,ans;
void dfs(int u){
    dep[u]=dep[fa[u]]+(sz[u]=1);
    go(u)if(v^fa[u]){
        fa[v]=u,dfs(v),sz[u]+=sz[v];
        if(sz[v]>sz[son[u]])son[u]=v;
    }
}
void dfs(int u,int t){
    Lx[u]=++dft;top[u]=t;if(son[u])dfs(son[u],t);
    go(u)if(v^fa[u]&&v^son[u])dfs(v,v);Rx[u]=dft;
}
inline int Go(int u,int p){
    while(top[u]^top[p]){
        if(fa[top[u]]==p)return top[u];
        u=fa[top[u]];
    }return top[u]==u?u:son[p];
}
inline void mdy(int i,int w){for(;i<=n;i+=i&-i)c[i]+=w;}
inline int qry(int i){int w=0;for(;i;i-=i&-i)w+=c[i];return w;}
inline void mdy(int L,int R,int w){mdy(L,w),mdy(R+1,-w);}
void sol(int b,int e,int s,int t,int L,int R){
    if(b>e||s>t)return;
    if(L==R){fp(i,s,t)ans[q[i].id]=h[L];return;}
    int mid=(L+R)>>1,tl=b,tr=e,sl=s,sr=t,j=b,sp;
    fp(i,s,t){
        for(;j<=e&&p[j].x<=q[i].x;++j)
            if(p[j].val>h[mid])tp[tr--]=p[j];
            else mdy(p[j].L,p[j].R,p[j].w),tp[tl++]=p[j];
        q[i].k>(sp=qry(q[i].y))?q[i].k-=sp,tq[sr--]=q[i]:tq[sl++]=q[i];
    }
    for(;j<=e;++j)if(p[j].val>h[mid])tp[tr--]=p[j];
        else mdy(p[j].L,p[j].R,p[j].w),tp[tl++]=p[j];
    fp(i,b,tr)mdy(tp[i].L,tp[i].R,-tp[i].w);
    fp(i,b,tr)p[i]=tp[i];fp(i,tl,e)p[e+tl-i]=tp[i];
    fp(i,s,sr)q[i]=tq[i];fp(i,sl,t)q[t+sl-i]=tq[i];
    sol(b,tr,s,sr,L,mid);sol(tl,e,sl,t,mid+1,R);
}
inline void add(int u,int v){static int ce=0;e[++ce]={fi[u],v},fi[u]=ce;}
int main(){
    #ifndef ONLINE_JUDGE
        file("s");
    #endif
    int u,v,w;sd(n),sd(w),sd(Q);
    fp(i,2,n)sd(u),sd(v),add(u,v),add(v,u);
    dfs(1),dfs(1,1);
    fp(i,1,w){
        sd(u),sd(v),sd(h[i]);
        if(Lx[u]>Lx[v])swap(u,v);
        if(Lx[u]<=Lx[v]&&Rx[v]<=Rx[u]){
            int z=Go(v,u);
            p[++m]={1,Lx[v],Rx[v],1,h[i]};
            p[++m]={Lx[z],Lx[v],Rx[v],-1,h[i]};
            if(Rx[z]<n)p[++m]={Lx[v],Rx[z]+1,n,1,h[i]},
                p[++m]={Rx[v]+1,Rx[z]+1,n,-1,h[i]};
        }else p[++m]={Lx[u],Lx[v],Rx[v],1,h[i]},p[++m]={Rx[u]+1,Lx[v],Rx[v],-1,h[i]};
    }sort(p+1,p+m+1);sort(h+1,h+w+1);h[0]=unique(h+1,h+w+1)-h-1;
    fp(i,1,Q){
        sd(u),sd(v),sd(w);
        if(Lx[u]>Lx[v])swap(u,v);
        q[i]={Lx[u],Lx[v],w,i};
    }sort(q+1,q+Q+1);
    sol(1,m,1,Q,1,h[0]);
    fp(i,1,Q)we(ans[i]);
return Ot(),0;
}

指针版 ( ( 写起来好像也没啥区别,应该是我不太会用吧 ) )

#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
    char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
    while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
template<class T>inline void we(T x){
    if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=2e5+5,inf=1e9;
typedef int arr[N];
struct eg{int nx,to;}e[N];
struct Line{
    int x,L,R,w,val;
    inline bool operator<(const Line b)const{return x<b.x;}
}Li[N],*p[N],*tp[N];
struct qry{
    int x,y,k,id;
    inline bool operator<(const qry b)const{return x<b.x;}
}Qr[N],*q[N],*tq[N];
int n,m,Q,dft;arr c,h,fa,fi,sz,Lx,Rx,dep,son,top,ans;
void dfs(int u){
    dep[u]=dep[fa[u]]+(sz[u]=1);
    go(u)if(v^fa[u]){
        fa[v]=u,dfs(v),sz[u]+=sz[v];
        if(sz[v]>sz[son[u]])son[u]=v;
    }
}
void dfs(int u,int t){
    Lx[u]=++dft;top[u]=t;if(son[u])dfs(son[u],t);
    go(u)if(v^fa[u]&&v^son[u])dfs(v,v);Rx[u]=dft;
}
inline int Go(int u,int p){
    while(top[u]^top[p]){
        if(fa[top[u]]==p)return top[u];
        u=fa[top[u]];
    }return top[u]==u?u:son[p];
}
inline void mdy(int i,int w){for(;i<=n;i+=i&-i)c[i]+=w;}
inline int qry(int i){int w=0;for(;i;i-=i&-i)w+=c[i];return w;}
inline void mdy(int L,int R,int w){mdy(L,w),mdy(R+1,-w);}
void sol(int b,int e,int s,int t,int L,int R){
    if(b>e||s>t)return;
    if(L==R){fp(i,s,t)ans[q[i]->id]=h[L];return;}
    int mid=(L+R)>>1,tl=b,tr=e,sl=s,sr=t,j=b,sp;
    fp(i,s,t){
        for(;j<=e&&p[j]->x<=q[i]->x;++j)
            if(p[j]->val>h[mid])tp[tr--]=p[j];
            else mdy(p[j]->L,p[j]->R,p[j]->w),tp[tl++]=p[j];
        q[i]->k>(sp=qry(q[i]->y))?q[i]->k-=sp,tq[sr--]=q[i]:tq[sl++]=q[i];
    }
    for(;j<=e;++j)if(p[j]->val>h[mid])tp[tr--]=p[j];
        else mdy(p[j]->L,p[j]->R,p[j]->w),tp[tl++]=p[j];
    fp(i,b,tr)mdy(tp[i]->L,tp[i]->R,-tp[i]->w);
    fp(i,b,tr)p[i]=tp[i];fp(i,tl,e)p[e+tl-i]=tp[i];
    fp(i,s,sr)q[i]=tq[i];fp(i,sl,t)q[t+sl-i]=tq[i];
    sol(b,tr,s,sr,L,mid);sol(tl,e,sl,t,mid+1,R);
}
inline void add(int u,int v){static int ce=0;e[++ce]={fi[u],v},fi[u]=ce;}
int main(){
    #ifndef ONLINE_JUDGE
        file("s");
    #endif
    int u,v,w;sd(n),sd(w),sd(Q);
    fp(i,2,n)sd(u),sd(v),add(u,v),add(v,u);
    dfs(1),dfs(1,1);
    fp(i,1,w){
        sd(u),sd(v),sd(h[i]);
        if(Lx[u]>Lx[v])swap(u,v);
        if(Lx[u]<=Lx[v]&&Rx[v]<=Rx[u]){
            int z=Go(v,u);
            Li[++m]={1,Lx[v],Rx[v],1,h[i]};
            Li[++m]={Lx[z],Lx[v],Rx[v],-1,h[i]};
            if(Rx[z]<n)Li[++m]={Lx[v],Rx[z]+1,n,1,h[i]},
                Li[++m]={Rx[v]+1,Rx[z]+1,n,-1,h[i]};
        }else Li[++m]={Lx[u],Lx[v],Rx[v],1,h[i]},Li[++m]={Rx[u]+1,Lx[v],Rx[v],-1,h[i]};
    }sort(Li+1,Li+m+1);fp(i,1,m)p[i]=Li+i;
    sort(h+1,h+w+1);h[0]=unique(h+1,h+w+1)-h-1;
    fp(i,1,Q){
        sd(u),sd(v),sd(w);
        if(Lx[u]>Lx[v])swap(u,v);
        Qr[i]={Lx[u],Lx[v],w,i};
    }
    sort(Qr+1,Qr+Q+1);fp(i,1,Q)q[i]=Qr+i;
    sol(1,m,1,Q,1,h[0]);fp(i,1,Q)we(ans[i]);
return Ot(),0;
}

写在最后:窝再也不敢乱卡常了 , , <script type="math/tex" id="MathJax-Element-128">,</script>写完后调试到绝望这里写图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值