• [Luogu3242][HNOI2015]接水果


    Luogu
    我今天做两道整体二分结果全都是BZOJ权限题???

    sol

    我们抓住“盘子的路径是水果的路径的子路径”这个条件。
    考虑每一个盘子路径((u,v)),讨论它可以作为哪些水果路径的子路径。
    如果说(u,v)不是祖孙关系,那么水果路径的两端点就必须分别在以(u)(v)为根的子树中。即若一个水果路径((a,b))满足((u,v))是它的子路径,则有(dfn_ule{dfn_a}le{low_u},dfn_vle{dfn_b}le{low_v})(请自行判断是否交换(u,v)(a,b)的顺序)
    其中(low_u)是以(u)为根的子树中的最大(dfn)序。
    如果(u,v)是祖孙关系,假设(u)是祖先,那么据路径的一端一定要在(v)的子树里,另一端的位置,要保证不在(w)的子树里,其中(w)(u)的直接儿子也是(v)的祖先(当然只有那一个啦)。
    所以就是要满足(1le{dfn_a}<dfn_wmbox{或}low_u<dfn_ale{n},dfn_vle{dfn_b}le{low_v})
    发现这个类似一个二维的矩形呀,所以就可以做一个扫描线,树状数组统计答案就可以了。
    把所有盘子视为一个或是两个矩形,按权值大小排序,每次二分一个位置判断某一点(一个水果)是否已经被(k)个矩形覆盖,然后向下递归即可。
    依旧是整体二分的板子

    code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 40005;
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    struct edge{int to,next;}a[N<<1];
    struct plate{
    	int x1,x2,y1,y2,v;
    	bool operator < (const plate &b) const
    		{return v<b.v;}
    }p[N<<1];
    struct fruit{
    	int x,y,k,id;
    	bool operator < (const fruit &b) const
    		{return x<b.x;}
    }q[N],q1[N],q2[N];
    struct node{
    	int x,y,v;
    	bool operator < (const node &b) const
    		{return x<b.x;}
    }zsy[N<<2];
    int n,P,Q,head[N],cnt,fa[N],dep[N],sz[N],son[N],top[N],dfn[N],low[N],tot,c[N],ans[N];
    void dfs1(int u,int f)
    {
    	fa[u]=f;dep[u]=dep[f]+1;sz[u]=1;
    	for (int e=head[u];e;e=a[e].next)
    	{
    		int v=a[e].to;if (v==f) continue;
    		dfs1(v,u);
    		sz[u]+=sz[v];if (sz[v]>sz[son[u]]) son[u]=v;
    	}
    }
    void dfs2(int u,int up)
    {
    	top[u]=up;dfn[u]=++cnt;
    	if (son[u]) dfs2(son[u],up);
    	for (int e=head[u];e;e=a[e].next)
    		if (a[e].to!=fa[u]&&a[e].to!=son[u])
    			dfs2(a[e].to,a[e].to);
    	low[u]=cnt;
    }
    int getlca(int u,int v)
    {
    	while (top[u]^top[v])
    	{
    		if (dep[top[u]]<dep[top[v]]) swap(u,v);
    		u=fa[top[u]];
    	}
    	return dep[u]<dep[v]?u:v;
    }
    int getson(int u,int v)
    {
    	int gg;
    	while (top[u]^top[v]) gg=top[v],v=fa[top[v]];
    	return u==v?gg:son[u];
    }
    void modify(int k,int v){while (k<=n) c[k]+=v,k+=k&-k;}
    int query(int k){int s=0;while (k) s+=c[k],k-=k&-k;return s;}
    void solve(int L,int R,int l,int r)//LR询问(水果)区间 lr二分答案区间
    {
    	if (L>R) return;
    	if (l==r)
    	{
    		for (int i=L;i<=R;i++)
    			ans[q[i].id]=p[l].v;
    		return;
    	}
    	int mid=l+r>>1,top=0,pos=0,t1=0,t2=0,temp;
    	for (int i=l;i<=mid;i++)
    	{
    		zsy[++top]=(node){p[i].x1,p[i].y1,1};
    		zsy[++top]=(node){p[i].x1,p[i].y2+1,-1};
    		zsy[++top]=(node){p[i].x2+1,p[i].y1,-1};
    		zsy[++top]=(node){p[i].x2+1,p[i].y2+1,1};
    	}
    	sort(zsy+1,zsy+top+1);
    	for (int i=L;i<=R;i++)
    	{
    		while (pos<top&&zsy[pos+1].x<=q[i].x)
    			pos++,modify(zsy[pos].y,zsy[pos].v);
    		temp=query(q[i].y);
    		if (q[i].k<=temp) q1[++t1]=q[i];
    		else q[i].k-=temp,q2[++t2]=q[i];
    	}
    	while (pos<top) pos++,modify(zsy[pos].y,zsy[pos].v);//记得这里要清空树状数组
    	for (int i=L,j=1;j<=t1;i++,j++) q[i]=q1[j];
    	for (int i=L+t1,j=1;j<=t2;i++,j++) q[i]=q2[j];
    	solve(L,L+t1-1,l,mid);solve(L+t1,R,mid+1,r);
    }
    int main()
    {
    	n=gi();P=gi();Q=gi();
    	for (int i=1,u,v;i<n;i++)
    	{
    		u=gi();v=gi();
    		a[++cnt]=(edge){v,head[u]};head[u]=cnt;
    		a[++cnt]=(edge){u,head[v]};head[v]=cnt;
    	}
    	dfs1(1,0);cnt=0;dfs2(1,1);
    	for (int i=1,u,v,w,gg;i<=P;i++)
    	{
    		u=gi();v=gi();w=gi();
    		if (dfn[u]>dfn[v]) swap(u,v);
    		if (getlca(u,v)==u)
    		{
    			gg=getson(u,v);
    			if (dfn[gg]>1) p[++tot]=(plate){1,dfn[gg]-1,dfn[v],low[v],w};
    			if (low[gg]<n) p[++tot]=(plate){dfn[v],low[v],low[gg]+1,n,w};
    		}
    		else p[++tot]=(plate){dfn[u],low[u],dfn[v],low[v],w};
    	}
    	sort(p+1,p+tot+1);
    	for (int i=1,u,v,k;i<=Q;i++)
    	{
    		u=gi();v=gi();k=gi();
    		if (dfn[u]>dfn[v]) swap(u,v);
    		q[i]=(fruit){dfn[u],dfn[v],k,i};
    	}
    	sort(q+1,q+Q+1);
    	solve(1,Q,1,tot);
    	for (int i=1;i<=Q;i++) printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    一次sqlldr性能测试案例
    Java过滤特殊字符的正则表达式
    朝阳自行成交过户流程
    direct=true 错误处理方法 (关于 Oracle 的数据导入导出及 Sql Loader (sqlldr) 的用法
    SQLLDR直接加载几个参数的测试
    处理超出打开游标的最大数异常(ORA01000: maximum open cursors exceeded)
    java 用PreparedStatement来setDate,用问号的形式给日期问号赋值
    linux下的文件结构介绍
    用SQLLDR来装载CLOB/BLOB列的控制文件例子
    关于oracle日期的说明
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8365346.html
Copyright © 2020-2023  润新知