zoukankan      html  css  js  c++  java
  • 【题解】[USACO17JAN]Promotion Counting P

    Problem

    ( ext{Solution:})

    题目求的就是一棵子树中大于根节点权值的节点数。

    这东西一看就很权值线段树。

    然后发现这东西又很线段树合并。

    考虑对每一个点维护一棵权值线段树。这样,我们将子树的信息合并到根的权值树上,就可以做到 (nlog n) 合并信息了。

    然后对每个节点进行查询即可。权值树上维护一下区间和即可。由于空间问题要动态开点。

    线段树合并的空间复杂度是 (O(nlog n)) 的,又有一个约为 (2) 的常数(从某处看到的)(这是动态开点线段树合并的复杂度)

    所以开到 (3.2cdot 10^6) 就可以了。

    懒得思考怎么直接求,实际上可以用差分的思想,更新完一棵子树后,用更新前的信息减去更新后的信息即可。这样用树状数组也可以解决问题。

    就当练习一下线段树合并了。

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=3.2e6+10;
    const int N=2e5+10;
    int head[MAXN],tot,cnt,n,m;
    int ls[MAXN],rs[MAXN],ans[MAXN];
    int dep[MAXN],pa[MAXN],siz[MAXN];
    int b[MAXN],bcnt,blen;
    int v[MAXN],val[MAXN];
    struct E{int nxt,to;}e[MAXN];
    inline void add(int x,int y){e[++tot]=(E){head[x],y};head[x]=tot;}
    int rt[MAXN],sum[MAXN];
    inline int getpos(int v){return lower_bound(b+1,b+blen+1,v)-b;}
    void dfs(int x,int fa){
    	dep[x]=dep[fa]+1;
    	siz[x]=1;
    	for(int i=head[x];i;i=e[i].nxt){
    		int j=e[i].to;
    		if(j==fa)continue;
    		dfs(j,x);siz[x]+=siz[j];
    	}
    }
    inline void pushup(int x){sum[x]=sum[ls[x]]+sum[rs[x]];}
    int change(int x,int l,int r,int pos,int v){
    	if(!x)x=++cnt;
    	if(l==r){
    		sum[x]+=v;
    		return x;
    	}
    	int mid=(l+r)>>1;
    	if(pos<=mid)ls[x]=change(ls[x],l,mid,pos,v);
    	else rs[x]=change(rs[x],mid+1,r,pos,v);
    	pushup(x);return x;
    }
    int merge(int x,int y,int l,int r){
    	if(!x||!y)return x+y;
    	if(l==r){
    		sum[x]+=sum[y];
    		return x;
    	}
    	int mid=(l+r)>>1;
    	ls[x]=merge(ls[x],ls[y],l,mid);
    	rs[x]=merge(rs[x],rs[y],mid+1,r);
    	pushup(x);return x;
    }
    int query(int x,int l,int r,int ql,int qr){
    	if(l>=ql&&r<=qr)return sum[x];
    	int mid=(l+r)>>1,ans=0;
    	if(ql<=mid)ans+=query(ls[x],l,mid,ql,qr);
    	if(mid<qr)ans+=query(rs[x],mid+1,r,ql,qr);
    	return ans;
    }
    void DFS(int x){
    	for(int i=head[x];i;i=e[i].nxt){
    		int j=e[i].to;
    		if(j==pa[x])continue;
    		DFS(j);
    		rt[x]=merge(rt[x],rt[j],1,N);
    	}
    	ans[x]=query(rt[x],1,N,val[x]+1,N);
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i)scanf("%d",&v[i]);
    	for(int i=1;i<=n;++i)b[++bcnt]=v[i];
    	sort(b+1,b+bcnt+1);
    	blen=unique(b+1,b+bcnt+1)-b-1;
    	for(int i=1;i<=n;++i){
    		int pos=getpos(v[i]);
    		val[i]=pos;
    	}
    	for(int i=1;i<=n;++i)rt[i]=change(rt[i],1,N,val[i],1);
    	for(int i=2;i<=n;++i){
    		int x;
    		scanf("%d",&x);
    		add(x,i);pa[i]=x;
    	}
    	dfs(1,0);
    	DFS(1);
    	for(int i=1;i<=n;++i)printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    【CJOJ1167】【洛谷1894】[USACO4.2]完美的牛栏
    【洛谷2055】【CJOJ2487】【ZJOI2009】 假期的宿舍
    【NOIP2012】【CJOJ1093】【洛谷1083】借教室
    如何正确的深蹲
    6种食物
    9大食物 你都吃过几种?
    食物
    如何正确蹲马步 蹲马步的正确方法
    这才是俯卧撑的正确做法!你真的会做俯卧撑吗?
    如何保持良好的状态
  • 原文地址:https://www.cnblogs.com/h-lka/p/14943417.html
Copyright © 2011-2022 走看看