P3242 [HNOI2015] 接水果
P3242 [HNOI2015] 接水果
题目描述
风见幽香非常喜欢玩一个叫做 osu! 的游戏,其中她最喜欢玩的模式就是接水果。由于她已经 DT FC 了 The big black,她觉得这个游戏太简单了,于是发明了一个更加难的版本。
首先有一个地图,是一棵由
这颗树上有
接下来依次会有
幽香每次需要选择一个盘子去接当前的水果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径。这里规定:从
当然为了提高难度,对于第
输入格式
第一行三个数
接下来
接下来
接下来
输出格式
对于每个果子,输出一行表示选择的盘子的权值。
数据范围
对于
Solution:
整体二分好题。
整体二分:
参考我们之前学过的二分答案这一思想,整体二分的还是而分一个答案,然后统计一下对于当前答案
问题转化:
首先分析一下这个反常识的题面,我们要用水果去接盘子。
如果盘子的路径是一条链:
我们会发现 (2,8) 这条路径会对起点在篮圈,终点在红圈内的点产生贡献。
我们假设盘子的起终点是
那么我们就可以用
再来看不在一条链上:
很显然路径 (x,y) 会对起点在
现在我们将起点看成 x轴,终点看成 y轴。那么我们的每个盘子就相当于给几个矩形插入了一个新的值,那么查询就是要查一个单点上的所有将其包含的矩形中,权值第
这是一个经典的扫描线,我们以后用树状数组实现一个前缀和,然后将矩形变为在前缀和数组上差分。
算法实现:
我们先将所有的区间修改和单点查询按照
我们需要实现一个 solve(L,R,l,R) 函数。表示只考虑权值在
然后我们考虑如何分治:
先说修改:
由于我们的修改是在前缀和数组上差分的,所以只要一条线的权值
我们记
如果
当一个 solve 函数运行到叶子
Code:
#include<bits/stdc++.h> const int N=4e4+5; const int lg=17; using namespace std; int n,m,p,tot,cnt; int t[N],dep[N],st[N],ed[N]; int f[N][lg+1],val[N],ans[N]; vector<int> E[N]; struct task{ int opt,x,l,r,k,v,id; bool operator <(const task &a)const{ return x==a.x ? opt < a.opt : x<a.x; } }q[N*5],ql[N*5],qr[N*5]; inline int lowbit(int x){return x&-x;} inline void upd(int x,int k) { for(;x<=n;x+=lowbit(x))t[x]+=k; } inline int sum(int x) { int res=0; for(;x;x-=lowbit(x))res+=t[x]; return res; } void dfs(int x,int fa) { dep[x]=dep[f[x][0]=fa]+1;st[x]=++tot; for(int j=1;j<=lg;j++)f[x][j]=f[f[x][j-1]][j-1]; for(int y : E[x])if(y!=fa)dfs(y,x);ed[x]=tot; } int LCA(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=lg;i>=0;i--)if(dep[f[x][i]]>=dep[y])x=f[x][i]; for(int i=lg;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; return x==y ? x : f[x][0]; } int find(int x,int y) { for(auto z : E[x])if(z!=f[x][0]&&st[z]<=st[y]&&st[y]<=ed[z])return z; } void solve(int L,int R,int l,int r)//id:[L,R] val:[l,r] { if(L>R)return; //cout<<L<<" "<<R<<":"<<l<<" "<<r<<"\n"; if(l==r){for(int i=L;i<=R;i++)ans[q[i].id]=val[l];return;} int mid=l+r>>1,tmp,cntl=0,cntr=0; for(int i=L;i<=R;i++) { if(q[i].opt==1) { if(q[i].k<=mid) { upd(q[i].l,q[i].v);upd(q[i].r+1,-q[i].v); ql[++cntl]=q[i]; }else qr[++cntr]=q[i]; } else { tmp=sum(q[i].l); if(q[i].k<=tmp)ql[++cntl]=q[i]; else q[i].k-=tmp,qr[++cntr]=q[i]; } } tmp=L-1; for(int i=1;i<=cntl;i++)q[++tmp]=ql[i]; for(int i=1;i<=cntr;i++)q[++tmp]=qr[i]; solve(L,L+cntl-1,l,mid);solve(L+cntl,R,mid+1,r); } void work() { cin>>n>>m>>p; for(int i=1,x,y;i<n;i++) { scanf("%d%d",&x,&y); E[x].emplace_back(y); E[y].emplace_back(x); } for(int u=1;u<=n;u++)reverse(E[u].begin(),E[u].end()); dfs(1,0); for(int i=1,x,y,k,z;i<=m;i++) { scanf("%d%d%d",&x,&y,&k);val[i]=k; if(st[x]>st[y])swap(x,y);int lca=LCA(x,y); if(x==lca) { z=find(x,y); if(1<st[z]) { q[++cnt]={1,1,st[y],ed[y],k,1,0}; q[++cnt]={1,st[z],st[y],ed[y],k,-1,0}; } if(ed[z]<n) { q[++cnt]={1,st[y],ed[z]+1,n,k,1,0}; q[++cnt]={1,ed[y]+1,ed[z]+1,n,k,-1,0}; } } else { q[++cnt]={1,st[x],st[y],ed[y],k,1,0}; q[++cnt]={1,ed[x]+1,st[y],ed[y],k,-1,0}; } } sort(val+1,val+1+m); int inf=unique(val+1,val+1+m)-val-1; for(int i=1;i<=cnt;i++)q[i].k=lower_bound(val+1,val+1+inf,q[i].k)-val; for(int i=1,x,y,k;i<=p;i++) { scanf("%d%d%d",&x,&y,&k); if(st[x]>st[y])swap(x,y); q[++cnt]={2,st[x],st[y],0,k,0,i}; } sort(q+1,q+1+cnt); solve(1,cnt,1,inf); for(int i=1;i<=p;i++) { printf("%d\n",ans[i]); } } int main() { work(); return 0; }