题意
给你一个树上路径集合S,S,每条路径有个权值
每次询问一条路径p:x→y,p:x→y,问他在SS中包含的路径中权值第小的是多少
题解
先考虑怎么判断一条路径是否被另一条路径包含
先求出这棵树的dfsdfs序,,记
考虑把一条路径u→vu→v投影成二维平面上的点(Lu,Lv),Lu<Lv(Lu,Lv),Lu<Lv
一..如果是在链上
那么包含的路径x→yx→y要满足1≤Lx≤Lu,Lv≤Ly≤Rv1≤Lx≤Lu,Lv≤Ly≤Rv
也就是要求点(Lx,Ly)(Lx,Ly)在矩形{(1,Lv),(Lu,Rv)}{(1,Lv),(Lu,Rv)}中
所以
一条路径包含多少条路径⇔⇔对应点被多少个矩形覆盖
后者可以按照xx排序扫描线然后维护坐标的前缀和求出
二..考虑在树上
如果lca(u,v)≠ulca(u,v)≠u
那么就要求路径pp满足在uu的子树里在vv的子树里
也就是
即(Lx,Ly)(Lx,Ly)在矩形{(Lu,Lv),(Ru,Rv)}{(Lu,Lv),(Ru,Rv)}里
2.2.如果lca(u,v)=ulca(u,v)=u
设zz是上的第一个点
那么就要求路径pp满足一个节点在子树内,,一个节点在子树外
也就是(Lx,Ly)(Lx,Ly)在矩形{(1,Lv),(Lz−1,Rv)}∪{(Lv,Rz+1),(Rv,n)}{(1,Lv),(Lz−1,Rv)}∪{(Lv,Rz+1),(Rv,n)}中
考虑怎么求解
如果只有一个询问我们可以二分一个答案
然后加入权值小于这个答案的路径对应的矩形,,然后判断被覆盖了多少次
如果询问很多我们就可以用整体二分
考虑怎么卡常
1.lca(u,v)=u⇔Lv∈[Lu,Ru]1.lca(u,v)=u⇔Lv∈[Lu,Ru]
2.2.找路径上第一个点可以用树剖,,比倍增快很多
维护yy坐标前缀和用树状数组即可
二分答案的区间应该是[1,P][1,P]而不是[1,∞][1,∞]
5.5.不要存矩形,,直接存扫描线
先在外面把点和扫描线按照xx排序然后在整体二分里面只要扫一下
7.two−pointer7.two−pointer时以点的xx坐标为基准会好写一些
整体二分中传下去的操作也要满足xx升序这样就不要每次排序了
用指针也许会快一些
非指针版
#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; }写在最后窝再也不敢乱卡常了,,写完后调试到绝望

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

432

被折叠的 条评论
为什么被折叠?



