zoukankan      html  css  js  c++  java
  • luoguP3242 [HNOI2015]接水果

    题意

    考虑整体二分。

    考虑路径((x,y))被路径((u,v))包含需要满足什么条件:

    (dfn_x)表示(x)(dfs)序,(low_x=dfn_x+size_x-1),即子树最后一个的(dfs)序。
    我们钦定(dfn_x<dfn_y,dfn_u<dfn_v)
    1.(lca(x,y)!=x)
    (u)需要在(x)的子树中,(v)需要在(y)的子树中,体现在(dfs)序上就是:
    (dfn_xleqslant dfn_uleqslant low_x,dfn_yleqslant dfn_vleqslant low_y)
    即一个左上角为((dfn_x,low_x)),右下角为((dfn_y,low_y))的矩形内所有((dfn_u,dfn_v))都可以覆盖((x,y))
    2.(lca(x,y)=x)
    这时(v)需要在(y)的子树中,而(u)需要不在(x)包含(y)的那颗子树中,我们设(z)(x)的儿子中子树包含(y)的那个,类比上面,我们能得到(注意(dfn_u<dfn_v)):
    (1leqslant dfn_uleqslant dfn_z-1,dfn_yleqslant dfn_vleqslant low_y||low_x+1leqslant dfn_vleqslant n,dfn_yleqslant dfn_uleqslant low_y)

    于是查一个点被多少路径包含即查询一个矩形内的点数,显然是扫描线。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    #define re register
    const int maxn=40010;
    int n,m,Q,cnt,tim,tot,num;
    int head[maxn],dfn[maxn],low[maxn],size[maxn],top[maxn],pre[maxn],dep[maxn],son[maxn],a[maxn],ans[maxn];
    struct edge{int to,nxt;}e[maxn<<1];
    struct Query{int op,x,y1,y2,k,id;}qr[maxn<<2],tmpql[maxn<<2],tmpqr[maxn<<2];
    inline int read()
    {
    	char c=getchar();int res=0,f=1;
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
    	return res*f;
    }
    inline bool cmp(Query a,Query b){return a.x==b.x?a.op<b.op:a.x<b.x;}
    inline void add(int u,int v)
    {
    	e[++cnt].nxt=head[u];
    	head[u]=cnt;
    	e[cnt].to=v;
    }
    void dfs1(int x,int fa)
    {
    	size[x]=1;dep[x]=dep[fa]+1;pre[x]=fa;
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		if(y==fa)continue;
    		dfs1(y,x);size[x]+=size[y];
    		if(size[y]>size[son[x]])son[x]=y;
    	}
    }
    void dfs2(int x,int tp)
    {
    	top[x]=tp;dfn[x]=++tim;
    	if(son[x])dfs2(son[x],tp);
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		if(y==son[x]||y==pre[x])continue;
    		dfs2(y,y);
    	}
    	low[x]=tim;
    }
    inline int lca(int x,int y)
    {
    	while(top[x]!=top[y])
    	{
    		if(dep[top[x]]<dep[top[y]])swap(x,y);
    		x=pre[top[x]];
    	}
    	return dep[x]<dep[y]?x:y;
    }
    inline int jump(int x,int goal)
    {
    	while(top[x]!=top[goal])
    	{
    		if(pre[top[x]]==goal)return top[x];
    		x=pre[top[x]];
    	}
    	return son[goal];
    }
    struct Tree_arry
    {
    	#define lowbit(x) (x&-x)
    	int a[maxn];
    	inline void add(int x,int k){for(int i=x;i<=n;i+=lowbit(i))a[i]+=k;}
    	inline int query(int x){int res=0;for(int i=x;i;i-=lowbit(i))res+=a[i];return res;}
    }tr;
    void solve(int L,int R,int l,int r)
    {
    	if(L>R)return;
    	if(l==r)
    	{
    		for(int i=L;i<=R;i++)if(qr[i].op==2)ans[qr[i].id]=l;
    		return;
    	}
    	int mid=(l+r)>>1,cntl=0,cntr=0;
    	for(re int i=L;i<=R;i++)
    	{
    		//cerr<<"!"<<' ';
    		if(qr[i].op==2)
    		{
    			int tmp=tr.query(qr[i].y1);
    			if(tmp>=qr[i].k)tmpql[++cntl]=qr[i];
    			else qr[i].k-=tmp,tmpqr[++cntr]=qr[i];
    		}
    		else
    		{
    			//cerr<<qr[i].y1<<' '<<qr[i].y2+1<<endl;
    			if(qr[i].k<=mid)tr.add(qr[i].y1,qr[i].op),tr.add(qr[i].y2+1,-qr[i].op),tmpql[++cntl]=qr[i];
    			else tmpqr[++cntr]=qr[i];
    			//cerr<<"end"<<endl;
    		} 
    	}
    	for(re int i=1;i<=cntl;i++)qr[L+i-1]=tmpql[i];
    	for(re int i=1;i<=cntr;i++)qr[L+cntl+i-1]=tmpqr[i];
    	solve(L,L+cntl-1,l,mid);solve(L+cntl,R,mid+1,r);
    }
    int main()
    {
    	n=read(),m=read(),Q=read();
    	for(re int i=1;i<n;i++)
    	{
    		int u=read(),v=read();
    		add(u,v),add(v,u);
    	}
    	dfs1(1,0),dfs2(1,1);
    	for(re int i=1;i<=m;i++)
    	{
    		int x=read(),y=read(),k=read(),z=lca(x,y);a[++num]=k;
    		if(dfn[x]>dfn[y])swap(x,y);
    		if(z==x)
    		{
    			int w=jump(y,x);
    			if(dfn[w]>1)
    			{
    				qr[++tot]=(Query){1,1,dfn[y],low[y],k,0};
    				qr[++tot]=(Query){-1,dfn[w],dfn[y],low[y],k,0};
    			}
    			if(low[w]<n)
    			{
    				qr[++tot]=(Query){1,dfn[y],low[w]+1,n,k,0};
    				qr[++tot]=(Query){-1,low[y]+1,low[w]+1,n,k,0};
    			}
    		}
    		else 
    		{
    			qr[++tot]=(Query){1,dfn[x],dfn[y],low[y],k,0};
    			qr[++tot]=(Query){-1,low[x]+1,dfn[y],low[y],k,0};
    		}
    	}
    	sort(a+1,a+num+1);num=unique(a+1,a+num+1)-(a+1);
    	for(re int i=1;i<=tot;i++)qr[i].k=lower_bound(a+1,a+num+1,qr[i].k)-a;
    	for(re int i=1;i<=Q;i++)
    	{
    		int x=read(),y=read(),k=read();
    		if(dfn[x]>dfn[y])swap(x,y);
    		qr[++tot]=(Query){2,dfn[x],dfn[y],0,k,i};
    	}
    	sort(qr+1,qr+tot+1,cmp);
    	solve(1,tot,1,num);
    	for(re int i=1;i<=Q;i++)printf("%d
    ",a[ans[i]]);
    	return 0;
    } 
    
  • 相关阅读:
    蓝桥杯历届试题 打印十字图 文字图形
    Cuckoo Hashing
    2006 飞行员配对(二分图最大匹配)
    Bad Hair Day(求数组中元素和它后面离它最近元素之间的元素个数)
    2019CCPC江西省赛
    字典树系统学习
    ac自动机学习
    项目管理(把与某点相邻边分为两类 是复杂度降为(n^(3/2))
    Ultra-QuickSort(离散化)
    Chika and Friendly Pairs(莫队+树状数组+离散化+预处理上下界)
  • 原文地址:https://www.cnblogs.com/nofind/p/11982475.html
Copyright © 2011-2022 走看看