解析
一道有点毒瘤的题
也是一道感觉真的可以出现在考场上的很综合的题
做的还可以
除了一开始把盘子和水果看反白写了各树套树之外
为什么盘子是水果的子路径啊
由于是做专题爬过来的多次询问区间第k小,想到整体二分
那么重点就是子路径的判定问题
发现,对于一个盘子 (u,v)(u,v)(u,v)
分两种情况:
- 一般路径,那么可以被接到的水果 (x,y)(x,y)(x,y) 的x和y必须分别在u和v的子树中,换句话说就是 dfnu≤dfnx≤dfnu+sizu−1&dfnv≤dfny≤dfnv+sizv−1dfn_u\le dfn_x\le dfn_u+siz_u-1 \& dfn_v\le dfn_y\le dfn_v+siz_v-1dfnu≤dfnx≤dfnu+sizu−1&dfnv≤dfny≤dfnv+sizv−1(对称同理)
- 返祖链,假设u是祖先,son是 (u,v)(u,v)(u,v) 上u下方的第一个儿子,此时接到的水果 (x,y)(x,y)(x,y) 必须满足x在son的子树外,y在v的子树内,也就是 (dfnu≤dfnx<dfnson∣∣dfnu>dfnson+sizson−1)&dfnv≤dfny≤dfnv+sizv−1(dfn_u\le dfn_x< dfn_{son}||dfn_u>dfn_{son}+siz_{son}-1) \& dfn_v\le dfn_y\le dfn_v+siz_v-1(dfnu≤dfnx<dfnson∣∣dfnu>dfnson+sizson−1)&dfnv≤dfny≤dfnv+sizv−1
那么我们把路径 (u,v)(u,v)(u,v) 抽象成二维平面上的一个点 (dfnu,dfnv)(dfn_u,dfn_v)(dfnu,dfnv) ,问题就变成了矩形加单点求和问题
由于本题是静态的,所以可以直接扫描线一个log解决
加上整体二分的log,总复杂度 O(nlog2n)O(n\log^2n)O(nlog2n)
注意数组不要开小!!
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=4e5+100;
const int mod=1e9+7;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
int n,m,Q;struct node{int to,nxt;
}p[N<<1];
int fi[N],cnt;
inline void addline(int x,int y){p[++cnt]=(node){y,fi[x]};fi[x]=cnt;return;
}
int pl[N][19],pos[N],siz[N],tim;
void dfs(int x,int f){pl[x][0]=f;for(int k=1;pl[x][k-1];k++) pl[x][k]=pl[pl[x][k-1]][k-1];pos[x]=++tim;siz[x]=1;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;dfs(to,x);siz[x]+=siz[to];}return;
}
inline int Lca(int x,int y,int op){if(pos[x]<=pos[y]&&pos[y]<=pos[x]+siz[x]-1){assert(op);return x;}for(int k=16;k>=0;k--){int o=pl[x][k];if(!o||(pos[o]<=pos[y]&&pos[y]<=pos[o]+siz[o]-1)) continue;x=o;}return op?pl[x][0]:x;
}struct ope{int op;int x,y,k,id;//op=2int h,l,r,w,f;//op=1
}q[N],q1[N],q2[N];
bool cmp1(ope a,ope b){return a.h<b.h;}
bool cmp2(ope a,ope b){return a.x<b.x;}
int w[N],f[N],tot;
inline void add(int p,int w){for(;p<=n;p+=p&-p) f[p]+=w;return;
}
inline int ask(int p){int res(0);for(;p;p-=p&-p) res+=f[p];return res;
}
int ans[N];
void print(ope o){if(o.op==1){printf(" change: h=%d (%d %d) w=%d op=%d\n",o.h,o.l,o.r,o.w,o.f);}else{printf(" ask: x=%d y=%d k=%d id=%d\n",o.x,o.y,o.k,o.id);}
}
void solve(int L,int R,int ql,int qr){//printf("solve: (%d %d) (%d %d)\n",L,R,ql,qr);if(ql>qr) return;if(L==R){for(int i=ql;i<=qr;i++){if(q[i].op==2) ans[q[i].id]=L;}return;}int mid=(L+R)>>1;int l=ql,r=ql;while(q[r].op==1&&r<=qr) ++r;while(r<=qr){while(l<=qr&&q[l].op==1&&q[l].h<=q[r].x){if(q[l].w<=mid){add(q[l].l,q[l].f);add(q[l].r+1,-q[l].f); //printf(" add:l=%d (%d %d) f=%d\n",l,q[l].l,q[l].r,q[l].f);}++l;}w[q[r].id]+=ask(q[r].y);++r;}int pl=ql,n1(0),n2(0);for(;pl<=qr&&q[pl].op==1;++pl){if(q[pl].w<=mid){q1[++n1]=q[pl];if(pl<l){add(q[pl].l,-q[pl].f);add(q[pl].r+1,q[pl].f); //printf(" del:pl=%d (%d %d) f=%d\n",pl,q[pl].l,q[pl].r,q[pl].f);}}else q2[++n2]=q[pl];}for(;pl<=qr;pl++){int c=w[q[pl].id];if(c>=q[pl].k) q1[++n1]=q[pl];else{q[pl].k-=c;q2[++n2]=q[pl];}}for(int i=ql;i<=qr;i++){if(q[i].op==2) w[q[i].id]=0;}for(int i=1;i<=n1;i++) q[ql+i-1]=q1[i];for(int i=1;i<=n2;i++) q[ql+n1+i-1]=q2[i];solve(L,mid,ql,ql+n1-1);solve(mid+1,R,ql+n1,qr);return;
}
signed main(){
#ifndef ONLINE_JUDGE//freopen("a.in","r",stdin);//freopen("a.out","w",stdout);
#endif//printf("%d\n",(int)sizeof(tr)/1024/1024);memset(fi,-1,sizeof(fi));cnt=-1;n=read();m=read();Q=read();for(int i=1;i<n;i++){int x=read(),y=read();addline(x,y);addline(y,x);}dfs(1,0);for(int i=1;i<=m;i++){int x=read(),y=read(),w=read(),lca=Lca(x,y,1);//printf("i=%d (%d %d)\n",i,x,y);if(lca!=x) swap(x,y);if(lca==x){int tp=Lca(y,x,0);q[++tot]=(ope){1,0,0,0,0,pos[y],1,pos[tp]-1,w,1};//print(q[tot]);q[++tot]=(ope){1,0,0,0,0,pos[y],pos[tp]+siz[tp],n,w,1};//print(q[tot]);q[++tot]=(ope){1,0,0,0,0,pos[y]+siz[y],1,pos[tp]-1,w,-1};//print(q[tot]);q[++tot]=(ope){1,0,0,0,0,pos[y]+siz[y],pos[tp]+siz[tp],n,w,-1};//print(q[tot]);} else{q[++tot]=(ope){1,0,0,0,0,pos[y],pos[x],pos[x]+siz[x]-1,w,1};//print(q[tot]);q[++tot]=(ope){1,0,0,0,0,pos[y]+siz[y],pos[x],pos[x]+siz[x]-1,w,-1};//print(q[tot]);}}int pp=tot;for(int i=1;i<=Q;i++){int x=read(),y=read(),k=read();q[++tot]=(ope){2,pos[x],pos[y],k,i,0,0,0,0,0};q[++tot]=(ope){2,pos[y],pos[x],k,i,0,0,0,0,0};}sort(q+1,q+pp+1,cmp1);sort(q+pp+1,q+1+tot,cmp2);solve(0,1e9,1,tot);for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);return 0;
}
/*
*/