题目链接
题目解法
我们发现一段路径包含另一条不好做,但是被包含的关系就比较简单
对于每个盘子,我们可以分成 2 类情况,这里可以预处理出dfn序,令st[u]为进入u的时间,ed[u]为出去u的时间
- lca(a,b)=a(这里假设a是b的祖先),令k为a的儿子,且为b的祖先
画图可以发现,a-b被包含当且仅当另一条路径一个点在[ st[b],ed[b] ],即b的子树中
另一个点在[ 1,st[k]-1 ] 或 [ ed[k]+1,n ] 中,即不在k的子树中 - lca(a,b)≠a且lca(a,b)≠b
a-b被包含当且仅当另一条路径一个点在[ st[a],ed[a] ],即a的子树中
另一个点在[ st[b],ed[b] ],即b的子树中
上面的东西可以用树套树维护一下,询问的时候二分一下,时间复杂度
考虑更优的做法
我们发现每次询问都会进行二分,于是可以采用整体二分的思想
我们发现每个盘子会对1-2个矩阵做出贡献,那么可以考虑用扫描线
时间复杂度
这启发我们一些树套树2个区间的问题可以转化为矩阵的问题进行求解
#include <bits/stdc++.h>
#define lowbit(x) x&-x
#define swap(x,y) x^=y^=x^=y
using namespace std;
const int N(40100),P(40100),Q(40100),inf(1e9+5);
struct Modify{
int col,l,r,c,t;
}modify[P<<2],mL[P<<2],mR[P<<2];
struct Query{
int u,v,k,id,ans;
}query[Q],qL[Q],qR[Q];
int n,p,q,ANS[Q];
int dfn[N],idx,siz[N],depth[N],up[N][18];
vector<int> vec[N];
struct BIT{
int tr[N];
void add(int x,int k){
for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=k;
}
int ask(int x){
int res=0;
for(int i=x;i;i-=lowbit(i)) res+=tr[i];
return res;
}
}bit;
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar())
if(ch=='-')
RR=-1;
for(;isdigit(ch);ch=getchar())
FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
void dfs(int u){
dfn[u]=++idx,siz[u]=1;
for(int i=0;i<vec[u].size();i++){
int v=vec[u][i];
if(v!=up[u][0]){
depth[v]=depth[u]+1,up[v][0]=u;
dfs(v);
siz[u]+=siz[v];
}
}
}
void solve(int l,int r,int Lm,int Rm,int Lq,int Rq){
if(Lq>Rq) return;
if(l==r){
for(int i=Lq;i<=Rq;i++) query[i].ans=l;
return;
}
int mid=(l+r)>>1;
int Msiz1=0,Msiz2=0;
for(int i=Lm;i<=Rm;i++){
if(modify[i].c<=mid) mL[++Msiz1]=modify[i];
else mR[++Msiz2]=modify[i];
}
for(int i=1;i<=Msiz1;i++) modify[i+Lm-1]=mL[i];
for(int i=1;i<=Msiz2;i++) modify[i+Lm+Msiz1-1]=mR[i];
// cout<<Lm<<' '<<Rm<<'\n';
// cout<<l<<' '<<r<<" : "<<Msiz1<<'\n';
int Qsiz1=0,Qsiz2=0,j=1;
for(int i=Lq;i<=Rq;i++){
while(j<=Msiz1&&mL[j].col<=query[i].u){
bit.add(mL[j].l,mL[j].t);
bit.add(mL[j].r+1,-mL[j].t);
j++;
}
int res=bit.ask(query[i].v);
if(res>=query[i].k) qL[++Qsiz1]=query[i];//往l-mid走
else qR[++Qsiz2]=query[i],qR[Qsiz2].k-=res;//往mid+1-r走
}
for(int i=1;i<j;i++){
bit.add(mL[i].l,-mL[i].t);
bit.add(mL[i].r+1,mL[i].t);
}
for(int i=1;i<=Qsiz1;i++) query[i+Lq-1]=qL[i];
for(int i=1;i<=Qsiz2;i++) query[i+Lq+Qsiz1-1]=qR[i];
solve(l,mid,Lm,Lm+Msiz1-1,Lq,Lq+Qsiz1-1);
solve(mid+1,r,Lm+Msiz1,Rm,Lq+Qsiz1,Rq);
}
bool cmp1(const Modify &x,const Modify &y){
return x.col<y.col;
}
bool cmp2(const Query &x,const Query &y){
return x.u<y.u;
}
int get_lca(int x,int y){
if(depth[x]>depth[y]) swap(x,y);
for(int i=16;i>=0;i--)
if(depth[up[y][i]]>depth[x]) y=up[y][i];
if(up[y][0]==x) return y;
y=up[y][0];
for(int i=16;i>=0;i--)
if(up[x][i]!=up[y][i]) x=up[x][i],y=up[y][i];
return x;
}
int main(){
n=read(),p=read(),q=read();
for(int i=1,x,y;i<n;i++){
x=read(),y=read();
vec[x].push_back(y),vec[y].push_back(x);
}
dfs(1);
for(int j=1;j<=16;j++)
for(int i=1;i<=n;i++)
up[i][j]=up[up[i][j-1]][j-1];
int tot=0;
for(int i=1,a,b,c;i<=p;i++){
a=read(),b=read(),c=read();
if(dfn[a]<dfn[b]) swap(a,b);//保证dfn[b]<dfn[a]
int below=get_lca(a,b),lca=up[below][0];
if(lca!=a&&lca!=b){//a,b不成祖孙关系
modify[++tot]={dfn[b],dfn[a],dfn[a]+siz[a]-1,c,1};
modify[++tot]={dfn[b]+siz[b],dfn[a],dfn[a]+siz[a]-1,c,-1};
}
else{
modify[++tot]={1,dfn[a],dfn[a]+siz[a]-1,c,1};
modify[++tot]={dfn[below],dfn[a],dfn[a]+siz[a]-1,c,-1};
if(dfn[below]+siz[below]<=n){
modify[++tot]={dfn[a],dfn[below]+siz[below],n,c,1};
modify[++tot]={dfn[a]+siz[a],dfn[below]+siz[below],n,c,-1};
}
}
}
sort(modify+1,modify+tot+1,cmp1);
// for(int i=1;i<=tot;i++)
// cout<<modify[i].col<<' '<<modify[i].l<<' '<<modify[i].r<<' '<<modify[i].c<<' '<<modify[i].t<<'\n';
for(int i=1,u,v,k;i<=q;i++){
u=read(),v=read(),k=read();
if(dfn[u]>dfn[v]) swap(u,v);
query[i]={dfn[u],dfn[v],k,i};
}
sort(query+1,query+q+1,cmp2);
solve(1,inf,1,tot,1,q);
for(int i=1;i<=q;i++) ANS[query[i].id]=query[i].ans;
for(int i=1;i<=q;i++) printf("%d\n",ANS[i]);
return 0;
}