• ●BZOJ 2588 Spoj 10628. Count on a tree


    题链:

    http://www.lydsy.com/JudgeOnline/problem.php?id=2588

    题解:

    主席树,在线,(求LCA)
    感觉主席树真的好厉害。。。
    在原树上建主席树。
    即对于原树的节点 u ,它所对应的线段树维护的是原树中它到根的路径上的点的权值信息。
    即建主席树时, u 的线段树是由 fa[u] 的线段树而来的。
    然后对于询问的两个点 a,b,
    得到其 LCA,记为 c,并令 d = fa[c]
    那么 a 到 b 路径上的信息即为
    a 对应的线段树 + b 对应的线段树 - c 对应的线段树 - d 对应的线段树
    所以在主席树中直接查询第 K 小就好了。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define MAXN 100500
    #define filein(x) freopen(#x".in","r",stdin)
    #define fileout(x) freopen(#x".out","w",stdout)
    using namespace std;
    int A[MAXN],tmp[MAXN],bgs[MAXN],top[MAXN],dep[MAXN],fa[MAXN];
    int N,M,tnt;
    struct Edge{
    	int to[MAXN*2],nxt[MAXN*2],head[MAXN],ent;
    	void Reset(){
    		ent=2;
    		memset(head,0,sizeof(head));
    	}
    	void Adde(int u,int v){
    		to[ent]=v; nxt[ent]=head[u]; head[u]=ent++; 
    		to[ent]=u; nxt[ent]=head[v]; head[v]=ent++;
    	}
    }E;
    struct CMT{
    	int rt[MAXN],ls[MAXN*20],rs[MAXN*20],cnt[MAXN*20],sz;
    	void Insert(int &u,int l,int r,int p){
    		sz++; ls[sz]=ls[u]; rs[sz]=rs[u]; cnt[sz]=cnt[u];
    		u=sz; cnt[u]++; if(l==r) return;
    		int mid=(l+r)>>1; 
    		if(p<=mid) Insert(ls[u],l,mid,p);
    		else Insert(rs[u],mid+1,r,p);
    	}
    	int Query(int a,int b,int c,int d,int l,int r,int K){
    		if(l==r) return l;
    		int mid=(l+r)>>1,lcnt=cnt[ls[a]]+cnt[ls[b]]-cnt[ls[c]]-cnt[ls[d]];
    		if(K<=lcnt) return Query(ls[a],ls[b],ls[c],ls[d],l,mid,K);
    		else return Query(rs[a],rs[b],rs[c],rs[d],mid+1,r,K-lcnt);
    	}
    }DT;
    void read(int &x){
    	static int f; static char ch;
    	x=0; f=1; ch=getchar();
    	while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();}
    	while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	x=x*f;
    }
    void dfs1(int u,int dad){
    	static int num[MAXN];
    	DT.rt[u]=DT.rt[dad];
    	DT.Insert(DT.rt[u],1,tnt,A[u]);
    	num[u]=1; fa[u]=dad; int bgn=0;
    	for(int i=E.head[u],v;i;i=E.nxt[i]){
    		v=E.to[i]; if(v==dad) continue;
    		dfs1(v,u); num[u]+=num[v];
    		if(num[v]<=bgn) continue;
    		bgs[u]=v; bgn=num[v];
    	}
    }
    void dfs2(int u,int tp){
    	top[u]=tp; dep[u]=dep[fa[u]]+1;
    	if(bgs[u]) dfs2(bgs[u],tp);
    	for(int i=E.head[u],v;i;i=E.nxt[i]){
    		v=E.to[i]; if(v==fa[u]||v==bgs[u]) continue;
    		dfs2(v,v);
    	}
    }
    int lca(int u,int v){
    	while(top[u]!=top[v]){
    		if(dep[top[u]]>dep[top[v]]) swap(u,v);
    		v=fa[top[v]];
    	}
    	if(dep[u]>dep[v]) swap(u,v);
    	return u;
    }
    void solve(){
    	int lastANS=0,a,b,c,d,rta,rtb,rtc,rtd,K,p;
    	for(int i=1;i<=M;i++){
    		read(a); read(b); read(K);
    		a^=lastANS; c=lca(a,b); d=fa[c];
    		rta=DT.rt[a]; rtb=DT.rt[b];
    		rtc=DT.rt[c]; rtd=DT.rt[d];
    		p=DT.Query(rta,rtb,rtc,rtd,1,tnt,K);
    		lastANS=tmp[p];
    		printf("%d",lastANS);
    		if(i!=M) printf("
    ");
    	}
    }
    int main(){
    	E.Reset();
    	read(N); read(M);
    	for(int i=1;i<=N;i++) 
    		read(A[i]),tmp[i]=A[i];
    	sort(tmp+1,tmp+N+1); 
    	tnt=unique(tmp+1,tmp+N+1)-tmp-1;
    	for(int i=1;i<=N;i++)
    		A[i]=lower_bound(tmp+1,tmp+tnt+1,A[i])-tmp;
    	for(int i=1,u,v;i<N;i++)
    		scanf("%d%d",&u,&v),E.Adde(u,v);
    	dfs1(1,0);
    	dfs2(1,1);
    	solve();
    	return 0;
    }

  • 相关阅读:
    MySQL——索引
    MySQL——逻辑分层与存储引擎
    APP测试总结
    如何提高测试的质量
    测试用例的基础
    opencv图像处理常用操作一
    【bug】【Cannot find reference 'imread' in '__init__.py | __init__.py'】
    Numpy学习笔记
    工业互联网
    Python基本的数据清洗
  • 原文地址:https://www.cnblogs.com/zj75211/p/8068044.html
Copyright © 2020-2023  润新知