[整体二分 || 树套树 || 点分治] BZOJ 4009 [HNOI2015]接水果

整体二分的做法题解很多:http://blog.csdn.net/thy_asdf/article/details/50363672


点分治么 还不会233


树套树么 ORZ



打的整体二分


#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=100005;

namespace TREE{
	#define V G[p].v
	struct edge{
		int u,v,next;
	};
	edge G[N<<1];
	int head[N],inum;
	inline void add(int u,int v,int p){
		G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
	}
	int clk;
	int size[N],pre[N],last[N],fat[N][21],depth[N];
	inline void dfs(int u,int fa){
		size[u]=1; pre[u]=++clk; depth[u]=depth[fa]+1; fat[u][0]=fa;
		for (int k=1;k<=20;k++) fat[u][k]=fat[fat[u][k-1]][k-1]; 
		for (int p=head[u];p;p=G[p].next)
			if (V!=fa)
				dfs(V,u),size[u]+=size[V];
		last[u]=pre[u]+size[u]-1;
	}
	inline int LCA(int u,int v){  
	    if (depth[u]<depth[v]) swap(u,v);  
	    for (int k=20;~k;k--)  
	        if ((depth[u]-depth[v])&(1<<k))  
	            u=fat[u][k];  
	    if (u==v) return u;  
	    for (int k=20;~k;k--)  
	        if (fat[u][k]!=fat[v][k])  
	            u=fat[u][k],v=fat[v][k];  
	    return fat[u][0];  
	}
	inline int SecLCA(int x,int y){  
    	for (int k=20;~k;k--)  
        	if (depth[fat[x][k]]>depth[y])  
            	x=fat[x][k];  
    	return x;  
	}
}

int n,P,Q;
int ans[N];

struct Query{
	int x,y,k;
	int idx;
}que[N],tmp[N];
int qtot;

struct Matrix{
	int x1,x2,y1,y2,key;
	bool operator < (const Matrix &B) const{
		return key<B.key;
	}
}mat[N<<1];
int mtot;

namespace BIT{
	#define lowbit(x) ((x)&-(x))
	int c[N];
	inline void add(int x,int t){
		for (int i=x;i<=n;i+=lowbit(i))
			c[i]+=t;
	}
	inline void add(int l,int r,int t){
		add(l,t); add(r+1,-t);
	}
	inline int query(int x){
		int ret=0;
		for (int i=x;i;i-=lowbit(i))
			ret+=c[i];
		return ret;
	}
}

struct event{
	int x,y1,y2,r;
	event() { }
	event(int x,int y1,int y2,int r):x(x),y1(y1),y2(y2),r(r) { }
	bool operator < (const event &B) const{
		return x==B.x?(r>B.r):(x<B.x);
	}
}eve[N<<2];
int tot;

int cnt[N<<2];

inline void Solve(int l,int r,int ql,int qr){
	if (l==r){
		for (int i=ql;i<=qr;i++) ans[que[i].idx]=mat[l].key;
		return;
	}
	int mid=(l+r)>>1;
	tot=0;
	for (int i=l;i<=mid;i++) eve[++tot]=event(mat[i].x1,mat[i].y1,mat[i].y2,1),eve[++tot]=event(mat[i].x2,mat[i].y1,mat[i].y2,-1);
	for (int i=ql;i<=qr;i++) eve[++tot]=event(que[i].x,que[i].y,i,0);
	sort(eve+1,eve+tot+1);
	for (int i=1;i<=tot;i++)
		if (eve[i].r==1)
			BIT::add(eve[i].y1,eve[i].y2,1);
		else if (eve[i].r==-1)
			BIT::add(eve[i].y1,eve[i].y2,-1);
		else if (eve[i].r==0)
			cnt[eve[i].y2]=BIT::query(eve[i].y1);
	int L=ql-1,R=qr+1;
	for (int i=ql;i<=qr;i++)
		if (cnt[i]<que[i].k)
			tmp[--R]=que[i],tmp[R].k-=cnt[i];
		else
			tmp[++L]=que[i];
	for (int i=ql;i<=qr;i++)
		que[i]=tmp[i];
	if (ql<=L) Solve(l,mid,ql,L);
	if (R<=qr) Solve(mid+1,r,R,qr);
}

int main()
{
	using namespace TREE;
	int iu,iv,ik,w,lca;
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(n); read(P); read(Q);
	for (int i=1;i<n;i++)
		read(iu),read(iv),add(iu,iv,++inum),add(iv,iu,++inum);
	dfs(1,0);
	for (int i=1;i<=P;i++)
	{
		read(iu); read(iv); read(ik);
		if (pre[iu]>pre[iv]) swap(iu,iv);
		if ((lca=LCA(iu,iv))==iu)
		{
			w=SecLCA(iv,iu);
			if (pre[w]-1>0)
			{
				mat[++mtot].key=ik;
				mat[mtot].x1=1; mat[mtot].x2=pre[w]-1; mat[mtot].y1=pre[iv]; mat[mtot].y2=last[iv];
			}
			if (last[w]+1<=n)
			{
				mat[++mtot].key=ik;
				mat[mtot].x1=pre[iv]; mat[mtot].x2=last[iv]; mat[mtot].y1=last[w]+1; mat[mtot].y2=n; 
			}
		}
		else
		{
			mat[++mtot].key=ik;
			mat[mtot].x1=pre[iu]; mat[mtot].x2=last[iu]; mat[mtot].y1=pre[iv]; mat[mtot].y2=last[iv];
		}
	}
	sort(mat+1,mat+mtot+1);
	for (int i=1;i<=Q;i++)
	{
		read(iu); read(iv); read(ik);
		if (pre[iu]>pre[iv]) swap(iu,iv);
		que[++qtot].k=ik; que[qtot].x=pre[iu]; que[qtot].y=pre[iv]; que[qtot].idx=i;
	}
	Solve(1,mtot,1,qtot);
	for (int i=1;i<=Q;i++) printf("%d\n",ans[i]);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值