zoukankan      html  css  js  c++  java
  • ●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;
    }

  • 相关阅读:
    boost::asio在VS2008下的编译错误
    Java集合框架——接口
    ACM POJ 3981 字符串替换(简单题)
    ACM HDU 1042 N!(高精度计算阶乘)
    OneTwoThree (Uva)
    ACM POJ 3979 分数加减法(水题)
    ACM HDU 4004 The Frog's Games(2011ACM大连赛区第四题)
    Hexadecimal View (2011ACM亚洲大连赛区现场赛D题)
    ACM HDU 4002 Find the maximum(2011年大连赛区网络赛第二题)
    ACM HDU 4001 To Miss Our Children Time (2011ACM大连赛区网络赛)
  • 原文地址:https://www.cnblogs.com/zj75211/p/8068044.html
Copyright © 2011-2022 走看看