zoukankan      html  css  js  c++  java
  • 7076. 【2021.05.08 NOI模拟】膜拜

    给出两个点数相同的树。若干次询问,每次给出一个点集(([1,n])中的数,一个数表示着两棵树上对应的点),要求得到另一个包含这个点集的点集,满足该点集在两棵树上的点分别联通。

    给出权值(w_i),求答案点集的(sum w_i)

    (nle 10^5)


    一条链+一棵树的部分分做法:类似于之前的连续段问题处理即可(扫右端点,在左端点处维护连通块数,通过点-边得到连通块数,可以线段树上二分找到连续段。将询问丢入以左端点为关键字的大根堆中。对于当前右端点,找到最大左端点使其是连续段,处理左端点包含在其中的询问),时间(O(nlg n))

    正解:如果集合(S,T)合法,则(Sigcup T,Sigcap T)合法。在包含询问点集的极小连通块中,对于每条边((u,v)),找到包含(u,v)的极小合法点集,将它们并起来就是答案。

    (T_1)中的边((u,v))如果被选,需要(T_2)(u,v)路径上的所有边被选。反之类似。根据这种选什么就必须选什么这样的关系连有向边(此时原来的边视作一个点),从((u,v))对应点出发,能到达的所有点都要贡献。

    用ST表优化连边,跑Tarjan即可。时间(O(nlg n))

    也可以树剖优化连边,时间(O(nlg^2 n))但跑得极快。(不过应该也可知用全局平衡二叉树得到(O(nlg n))


    using namespace std;
    #include <bits/stdc++.h>
    #define N 100005
    #define M (N*40)
    #define fi first
    #define se second
    #define mp make_pair
    int n,Q;
    int w[N];
    struct EDGE{
    	int to;
    	EDGE *las;
    };
    template<int V,int E>
    struct Graph{
    	EDGE e[E];
    	int ne;
    	EDGE *last[V];
    	void link(int u,int v){
    		e[ne]=(EDGE){v,last[u]};
    		last[u]=e+ne++;
    	}
    };
    Graph<M,M*2> F;
    int m,c[M];
    struct Tree{
    	Graph<N,N*2> G;
    	int fa[N][18],dep[N],id[N][18];
    	void predfs(int x){
    		for (int i=1;1<<i<=dep[x];++i){
    			fa[x][i]=fa[fa[x][i-1]][i-1];
    			c[++m]=max(c[id[x][i-1]],c[id[fa[x][i-1]][i-1]]);
    			id[x][i]=m;
    			F.link(id[x][i],id[x][i-1]);
    			F.link(id[x][i],id[fa[x][i-1]][i-1]);
    		}
    		for (EDGE *ei=G.last[x];ei;ei=ei->las)
    			if (ei->to!=fa[x][0]){
    				fa[ei->to][0]=x;
    				c[++m]=max(w[x],w[ei->to]);
    				id[ei->to][0]=m;
    				dep[ei->to]=dep[x]+1;
    				predfs(ei->to);
    			}
    	}
    	void init(){
    		for (int i=1;i<n;++i){
    			int u,v;
    			scanf("%d%d",&u,&v);
    			G.link(u,v),G.link(v,u);
    		}
    		predfs(1);
    	}
    	void lk(int x,int u,int v){
    		if (dep[u]<dep[v]) swap(u,v);
    		for (int k=dep[u]-dep[v],i=0;k;k>>=1,++i)
    			if (k&1){
    				F.link(x,id[u][i]);
    				u=fa[u][i];
    			}
    		if (u==v) return;
    		for (int i=17;i>=0;--i)
    			if (fa[u][i]!=fa[v][i]){
    				F.link(x,id[u][i]);
    				F.link(x,id[v][i]);
    				u=fa[u][i],v=fa[v][i];
    			}
    		F.link(x,id[u][0]);
    		F.link(x,id[v][0]);
    	}
    	int qry(int u,int v){
    		int res=0;
    		if (dep[u]<dep[v]) swap(u,v);
    		for (int k=dep[u]-dep[v],i=0;k;k>>=1,++i)
    			if (k&1){
    				res=max(res,c[id[u][i]]);
    				u=fa[u][i];
    			}
    		if (u==v) return res;
    		for (int i=17;i>=0;--i)
    			if (fa[u][i]!=fa[v][i]){
    				res=max(res,max(c[id[u][i]],c[id[v][i]]));
    				u=fa[u][i],v=fa[v][i];
    			}
    		res=max(res,max(c[id[u][0]],c[id[v][0]]));
    		return res;
    	}
    } T[2];
    int dfn[M],low[M],nowdfn;
    int st[M],tp;
    bool ins[M];
    void tarjan(int x){
    	dfn[x]=low[x]=++nowdfn;
    	st[++tp]=x;
    	ins[x]=1;
    	for (EDGE *ei=F.last[x];ei;ei=ei->las){
    		if (!dfn[ei->to]){
    			tarjan(ei->to),low[x]=min(low[x],low[ei->to]);
    			c[x]=max(c[x],c[ei->to]);
    		}
    		else if (ins[ei->to])
    			low[x]=min(low[x],dfn[ei->to]);
    		else
    			c[x]=max(c[x],c[ei->to]);
    	}
    	if (dfn[x]==low[x]){
    		int v=c[x];
    		for (int i=tp;st[i]!=x;--i)
    			v=max(v,c[st[i]]);
    		for (;st[tp]!=x;--tp)
    			ins[st[tp]]=0,c[st[tp]]=v;
    		ins[x]=0,c[x]=v,--tp;
    	}
    }
    int main(){
    	freopen("orz.in","r",stdin);
    	freopen("orz.out","w",stdout);
    	scanf("%d%d",&n,&Q);
    	for (int i=1;i<=n;++i)
    		scanf("%d",&w[i]);
    	T[0].init();
    	T[1].init();
    	for (int i=2;i<=n;++i){
    		T[1].lk(T[0].id[i][0],i,T[0].fa[i][0]);
    		T[0].lk(T[1].id[i][0],i,T[1].fa[i][0]);
    	}
    	for (int i=1;i<=m;++i)
    		if (!dfn[i])
    			tarjan(i);
    	while (Q--){
    		int k,rt,ans;
    		scanf("%d%d",&k,&rt);
    		ans=w[rt];
    		for (int i=1,x;i<k;++i){
    			scanf("%d",&x);
    			ans=max(ans,T[0].qry(rt,x));
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Linux文本检索命令grep笔记
    Linux文本检索命令grep笔记
    Linux文件查询笔记
    Linux文件查询笔记
    Linux文件默认权限和umask笔记
    Linux文件默认权限和umask笔记
    Linux关于文件的权限笔记
    Linux关于文件的权限笔记
    Linux文件操作实用笔记
    6.创建自定义菜单
  • 原文地址:https://www.cnblogs.com/jz-597/p/14747134.html
Copyright © 2011-2022 走看看