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