zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    mysqldump指定编码导出数据
    centos 自带mysql卸载时出现无法卸载情况
    Linux下如何彻底删除MySQL
    输出一行字符串中的最长单词---调用函数
    span设置固定宽度
    如何使用Reaver破解Wi-Fi网络的WPA密码
    kernel hexdump分析 (2.0)
    C++基础学习笔记----第七课(面向对象的基本概念)
    有关java中的final关键字
    测试framebuffer
  • 原文地址:https://www.cnblogs.com/AKMer/p/10427836.html
Copyright © 2011-2022 走看看