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
",ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/AKMer/p/10427836.html