BZOJ4009:[HNOI2015]接水果(整体二分版)
浅谈离线分治算法:https://www.cnblogs.com/AKMer/p/10415556.html
题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=4009
树套树写法:https://www.cnblogs.com/AKMer/p/10181501.html
把二维线段树部分改成整体二分就行了。
时间复杂度:\(O(nlog^2n)\)
空间复杂度:\(O(n)\)
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
#define low(i) ((i)&(-(i)))
const int maxn=4e4+5;
bool bo[maxn*5];
int n,P,Q,tot,cnt,sum;int f[maxn][17];
int now[maxn],pre[maxn<<1],son[maxn<<1];
int dep[maxn],siz[maxn],dfn[maxn],ans[maxn];
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
void add(int a,int b) {
pre[++tot]=now[a];
now[a]=tot,son[tot]=b;
}
void dfs(int fa,int u) {
siz[u]=1,dfn[u]=++cnt;
f[u][0]=fa,dep[u]=dep[fa]+1;
for(int i=1;i<17;i++)
f[u][i]=f[f[u][i-1]][i-1];
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(v!=fa)dfs(u,v),siz[u]+=siz[v];
}
struct Oper {
int opt,x,y1,y2,k;
Oper() {}
Oper(int _opt,int _x,int _y1,int _y2,int _k) {
opt=_opt,x=_x,y1=_y1,y2=_y2,k=_k;
}
bool operator<(const Oper &a)const {
if(x==a.x)return (opt!=0)>(a.opt!=0);
return x<a.x;
}
}p[maxn*5],tmp[maxn*5];
struct tree_array {
int c[maxn];
void add(int pos,int v) {
for(int i=pos;i<=n;i+=low(i))
c[i]+=v;
}
int query(int pos) {
int res=0;
for(int i=pos;i;i-=low(i))
res+=c[i];
return res;
}
}T;
void solve(int l,int r,int st,int ed) {
if(ed<st)return;
if(l==r) {
for(int i=st;i<=ed;i++)
if(!p[i].opt)ans[p[i].y2]=l;
return;
}
int mid=(l+r)>>1,num=0;
for(int i=st;i<=ed;i++)
if(p[i].opt) {
if(p[i].k<=mid) {
bo[i]=1,num++;
T.add(p[i].y1,p[i].opt);
T.add(p[i].y2+1,-p[i].opt);
}
else bo[i]=0;
}
else {
int res=T.query(p[i].y1);
if(res>=p[i].k)bo[i]=1,num++;
else bo[i]=0,p[i].k-=res;
}
for(int i=st;i<=ed;i++)
if(p[i].opt&&p[i].k<=mid) {
T.add(p[i].y1,-p[i].opt);
T.add(p[i].y2+1,p[i].opt);
}
int ED=st,ST=st+num;
for(int i=st;i<=ed;i++)
if(bo[i])tmp[ED++]=p[i];
else tmp[ST++]=p[i];
for(int i=st;i<=ed;i++)
p[i]=tmp[i];
solve(l,mid,st,ED-1),solve(mid+1,r,ED,ed);
}
int main() {
n=read(),P=read(),Q=read();
for(int i=1;i<n;i++) {
int x=read(),y=read();
add(x,y),add(y,x);
}
dfs(0,1);
for(int i=1;i<=P;i++) {
int u=read(),v=read(),c=read();
if(dfn[u]>dfn[v])swap(u,v);
if(dfn[u]+siz[u]-1>=dfn[v]+siz[v]-1) {
int pos=v;
for(int i=16;~i;i--)
if(dep[f[pos][i]]>dep[u])
pos=f[pos][i];
p[++sum]=Oper(1,1,dfn[v],dfn[v]+siz[v]-1,c);
p[++sum]=Oper(-1,dfn[pos],dfn[v],dfn[v]+siz[v]-1,c);
p[++sum]=Oper(1,dfn[v],dfn[pos]+siz[pos],n,c);
p[++sum]=Oper(-1,dfn[v]+siz[v],dfn[pos]+siz[pos],n,c);
}
else {
p[++sum]=Oper(1,dfn[u],dfn[v],dfn[v]+siz[v]-1,c);
p[++sum]=Oper(-1,dfn[u]+siz[u],dfn[v],dfn[v]+siz[v]-1,c);
}
}
for(int i=1;i<=Q;i++) {
int u=read(),v=read(),k=read();
if(dfn[u]>dfn[v])swap(u,v);
p[++sum]=Oper(0,dfn[u],dfn[v],i,k);
}
sort(p+1,p+sum+1);
solve(1,1e9,1,sum);
for(int i=1;i<=Q;i++)
printf("%d\n",ans[i]);
return 0;
}