[HNOI2015]接水果

本文介绍了一种树结构上的路径查询优化方法,通过DFS序和扫描线算法实现路径包含判断及权值查找,适用于大量路径查询场景。

题意

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

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


题解

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

先求出这棵树的dfsdfs,,Lu=dfnu,Ru=dfnu+szu1

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

..如果是在链上

那么包含uv的路径xyx→y要满足1LxLu,LvLyRv1≤Lx≤Lu,Lv≤Ly≤Rv

也就是要求点(Lx,Ly)(Lx,Ly)在矩形{(1,Lv),(Lu,Rv)}{(1,Lv),(Lu,Rv)}

所以

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

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

..考虑在树上

1.如果lca(u,v)ulca(u,v)≠u

那么就要求路径pp满足xuu的子树里,yvv的子树里

也就是LuLxRu,LvLyRv

(Lx,Ly)(Lx,Ly)在矩形{(Lu,Lv),(Ru,Rv)}{(Lu,Lv),(Ru,Rv)}

2.2.如果lca(u,v)=ulca(u,v)=u

zzuv上的第一个点

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

也就是(Lx,Ly)(Lx,Ly)在矩形{(1,Lv),(Lz1,Rv)}{(Lv,Rz+1),(Rv,n)}{(1,Lv),(Lz−1,Rv)}∪{(Lv,Rz+1),(Rv,n)}

考虑怎么求解

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

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

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

考虑怎么卡常

1.lca(u,v)=uLv[Lu,Ru]1.lca(u,v)=u⇔Lv∈[Lu,Ru]

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

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

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

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

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

7.twopointer7.two−pointer时以点的xx坐标为基准会好写一些

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

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;
}

写在最后:窝再也不敢乱卡常了,,写完后调试到绝望这里写图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值