题解 P3242 【[HNOI2015]接水果】
Owen_codeisking · · 题解
从下午三点开此题调到到七点,
而且我觉得这道题对于练整体二分非常的好,就是写的人有点少。
不过为什么盘子是水果的子路径才是接住啊。。。不应该盘子比水果大的嘛。。。
我们将此路径覆盖分两类讨论:
不妨令
1、
那么我们发现其实路径一个端点在
2、
那么一个点在
发现可以做一遍扫描线,直接暴力树套树。在内层线段树动态开点,然后二分答案,
那有没有更好的解法呢?发现没有离线,第
我们可以请出我们的整体二分!
然后正解就是扫描线+整体二分了。把矩形差分一下,然后区间加,单点查,套一个差分的树状数组就好了。时间复杂度
#include <bits/stdc++.h>
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int maxn=40000+10;
int n,m,Q,c[maxn],ans[maxn],mp[maxn],lim,head[maxn],to[maxn<<1],nxt[maxn<<1],tot,cnt;
int top[maxn],dep[maxn],siz[maxn],son[maxn],fa[maxn],st[maxn],ed[maxn],tim;
struct Query{
int op,x,l,r,k,v,id;
}q[maxn*5],q1[maxn*5],q2[maxn*5];
bool cmp(Query a,Query b){
if(a.x!=b.x) return a.x<b.x;
return a.op<b.op;
}
inline void read(int &x){
x=0;int f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
if(f==-1) x=-x;
}
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
inline void upd(int x,int y){
for(;x<=n;x+=lowbit(x)) c[x]+=y;
}
inline int sum(int x){
int ans=0;
for(;x;x-=lowbit(x)) ans+=c[x];
return ans;
}
inline void add(int x,int y){
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs1(int x,int f){
fa[x]=f;siz[x]=1;
dep[x]=dep[f]+1;
int maxson=-1;
for(int i=head[x],y;i;i=nxt[i]){
y=to[i];
if(y==f) continue;
dfs1(y,x);
siz[x]+=siz[y];
if(siz[y]>maxson){
maxson=siz[y];
son[x]=y;
}
}
}
void dfs2(int x,int topf){
top[x]=topf;
st[x]=++tim;
if(son[x]) dfs2(son[x],topf);
for(int i=head[x],y;i;i=nxt[i]){
y=to[i];
if(y==fa[x]||y==son[x]) continue;
dfs2(y,y);
}
ed[x]=tim;
}
int LCA(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
return x;
}
int getson(int x,int y){
while(top[x]!=top[y]){
if(fa[top[x]]==y) return top[x];
x=fa[top[x]];
}
return son[y];
}
void solve(int L,int R,int l,int r){
if(L>R) return ;
if(l==r){
for(int i=L;i<=R;i++)
if(q[i].op==2) ans[q[i].id]=mp[l];
return ;
}
int mid=(l+r)>>1,cnt1=0,cnt2=0,val;
for(int i=L;i<=R;i++){
if(q[i].op==1){
if(q[i].k<=mid){
upd(q[i].l,q[i].v);upd(q[i].r+1,-q[i].v);
q1[++cnt1]=q[i];
}
else q2[++cnt2]=q[i];
}
else {
val=sum(q[i].l);
if(val>=q[i].k) q1[++cnt1]=q[i];
else q[i].k-=val,q2[++cnt2]=q[i];
}
}
for(int i=1;i<=cnt1;i++) q[L+i-1]=q1[i];
for(int i=1;i<=cnt2;i++) q[L+i+cnt1-1]=q2[i];
solve(L,L+cnt1-1,l,mid);solve(L+cnt1,R,mid+1,r);
}
int main()
{
read(n),read(m),read(Q);
int x,y,z,l,r,k,lca;
for(int i=1;i<n;i++){
read(x),read(y);
add(x,y);add(y,x);
}
dfs1(1,0);dfs2(1,1);
for(int i=1;i<=m;i++){
read(x),read(y),read(k);mp[i]=k;
if(st[x]>st[y]) swap(x,y);
lca=LCA(x,y);
if(lca==x){
z=getson(y,x);
if(st[z]>1){
q[++cnt]=(Query){1,1,st[y],ed[y],k,1,0};
q[++cnt]=(Query){1,st[z],st[y],ed[y],k,-1,0};
}
if(ed[z]<n){
q[++cnt]=(Query){1,st[y],ed[z]+1,n,k,1,0};
q[++cnt]=(Query){1,ed[y]+1,ed[z]+1,n,k,-1,0};
}
}
else {
q[++cnt]=(Query){1,st[x],st[y],ed[y],k,1,0};
q[++cnt]=(Query){1,ed[x]+1,st[y],ed[y],k,-1,0};
}
}
sort(mp+1,mp+m+1);
lim=unique(mp+1,mp+m+1)-mp-1;
for(int i=1;i<=cnt;i++) q[i].k=lower_bound(mp+1,mp+lim+1,q[i].k)-mp;
for(int i=1;i<=Q;i++){
read(x),read(y),read(k);
if(st[x]>st[y]) swap(x,y);
q[++cnt]=(Query){2,st[x],st[y],0,k,0,i};
}
sort(q+1,q+cnt+1,cmp);
solve(1,cnt,1,lim);
for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);
return 0;
}