解析
一道有点毒瘤的题
也是一道感觉真的可以出现在考场上的很综合的题
做的还可以
除了一开始把盘子和水果看反白写了各树套树之外
为什么盘子是水果的子路径啊
由于是做专题爬过来的多次询问区间第k小,想到整体二分
那么重点就是子路径的判定问题
发现,对于一个盘子
(
u
,
v
)
(u,v)
(u,v)
分两种情况:
- 一般路径,那么可以被接到的水果 ( x , y ) (x,y) (x,y) 的x和y必须分别在u和v的子树中,换句话说就是 d f n u ≤ d f n x ≤ d f n u + s i z u − 1 & d f n v ≤ d f n y ≤ d f n v + s i z v − 1 dfn_u\le dfn_x\le dfn_u+siz_u-1 \& dfn_v\le dfn_y\le dfn_v+siz_v-1 dfnu≤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的子树内,也就是 ( d f n u ≤ d f n x < d f n s o n ∣ ∣ d f n u > d f n s o n + s i z s o n − 1 ) & d f n v ≤ d f n y ≤ d f n v + s i z v − 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) 抽象成二维平面上的一个点
(
d
f
n
u
,
d
f
n
v
)
(dfn_u,dfn_v)
(dfnu,dfnv) ,问题就变成了矩形加单点求和问题
由于本题是静态的,所以可以直接扫描线一个log解决
加上整体二分的log,总复杂度
O
(
n
log
2
n
)
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=2
int 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;
}
/*
*/