• 题解「GMOJ6898 【2020.11.27提高组模拟】第二题」


    题面

    GMOJ6898 【2020.11.27提高组模拟】第二题

    题解

    考虑非根结点 (u) 和它的父亲 (fa_u) ,若 (fa_u) 除了 (u) 所在的子树的其他子树中有其他黑点 (v) ,那么称 (fa_u)(v) 覆盖,并且 (fa_u) 会对以 (u) 为根的子树中的黑色节点产生贡献。对于每一个结点 (u) ,找出最早覆盖 (fa_u) 的结点 (v) ,统计出 (n-1) 个点对 ((u,v))

    从小到大加入黑点,查找当前加入的结点 (v) 覆盖了哪些结点,以及对应的点对 ((u,v)) ,对 (u) 的子树贡献加一,子树加用树状数组维护即可。处理完这些点对后,在树状数组上查找 (f_v) ,计入答案中。因为还要知道 (v) 对之前几个黑点产生了贡献,所以还要用一个树状数组统计子树内黑点个数。

    ( ext{Code}:)

    #include <cctype>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long lxl;
    const int maxn=8e5+5;
    const lxl mod=1e9+7;
    
    #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    char buf[1<<21],*p1=buf,*p2=buf;
    template <typename T>
    inline void read(T &x)
    {
    	x=0;T f=1;char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    	x*=f;
    }
    
    struct edge
    {
    	int u,v,next;
    	edge(int u,int v,int next):
    		u(u),v(v),next(next){}
    	edge(){}
    }e[maxn];
    
    int head[maxn],ecnt;
    
    inline void add(int u,int v)
    {
    	e[ecnt]=edge(u,v,head[u]);
    	head[u]=ecnt++;
    }
    
    int n,fa[maxn];
    int dfn[maxn],idx[maxn],siz[maxn],dfs_cnt;
    int Min[maxn],sMin[maxn],son[maxn];
    pair<int,int> pii[maxn];
    int pcnt;
    
    void dfs(int u)
    {
    	dfn[u]=++dfs_cnt;
    	idx[dfs_cnt]=u;
    	siz[u]=1;
    	Min[u]=u;
    	for(int i=head[u];~i;i=e[i].next)
    	{
    		int v=e[i].v;
    		dfs(v);
    		siz[u]+=siz[v];
    		if(Min[v]<Min[u]) sMin[u]=Min[u],Min[u]=Min[v],son[u]=v;
    		else if(Min[v]<sMin[u]) sMin[u]=Min[v];
    	}
    }
    
    namespace BIT
    {
    	int sum[maxn];
    	inline int lowbit(int x) {return x&-x;}
    	inline void add(int x,int d)
    	{
    		for(int i=x;i<=n;i+=lowbit(i))
    			sum[i]+=d;
    	}
    	inline int query(int x)
    	{
    		int res=0;
    		for(int i=x;i>=1;i-=lowbit(i))
    			res+=sum[i];
    		return res;
    	}
    	inline int query(int l,int r)
    	{
    		return query(r)-query(l-1);
    	}
    }
    
    namespace Segment_Tree
    {
    	int sum[maxn];
    	inline int lowbit(int x) {return x&-x;}
    	inline void add(int x,int d)
    	{
    		for(int i=x;i<=n;i+=lowbit(i))
    			sum[i]+=d;
    	}
    	inline int query(int x)
    	{
    		int res=0;
    		for(int i=x;i>=1;i-=lowbit(i))
    			res+=sum[i];
    		return res;
    	}
    	inline void modify(int l,int r,int d)
    	{
    		add(l,d);add(r+1,-d);
    	}
    }
    
    int main()
    {
    	freopen("dierti.in","r",stdin);
    	freopen("dierti.out","w",stdout);
    	read(n);
    	memset(head,-1,sizeof(head));
    	int rt;
    	for(int i=1;i<=n;++i)
    	{
    		read(fa[i]);
    		if(fa[i]) add(fa[i],i);
    		else rt=i;
    	}
    	dfs(rt);
    	for(int i=1;i<=n;++i) if(fa[i])
    		pii[++pcnt]=make_pair(son[fa[i]]==i?sMin[fa[i]]:Min[fa[i]],i);
    	sort(pii+1,pii+pcnt+1);
    	int ans=1,sum=0;
    	for(int i=1,p=1;i<=n;++i)
    	{
    		while(p<=pcnt&&pii[p].first<=i)
    		{
    			int u=pii[p].second;
    			Segment_Tree::modify(dfn[u],dfn[u]+siz[u]-1,1);
    			sum+=BIT::query(dfn[u],dfn[u]+siz[u]-1);
    			if(sum>=mod) sum-=mod;
    			++p;
    		}
    		BIT::add(dfn[i],1);
    		sum+=Segment_Tree::query(dfn[i])+1;
    		if(sum>=mod) sum-=mod;
    		ans=1ll*ans*sum%mod;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    git 创建项目
    【转载】Nginx-Lua模块的执行顺序
    【转】微信oauth授权过程
    vps
    【转载】centos安装字体
    【转载】TortoiseGit图标消失
    【转载】linux权限
    js 获取url 中的参数;
    手机下拉/上拉刷新(基于jq或者zepto)
    vscode快捷键
  • 原文地址:https://www.cnblogs.com/syc233/p/14051999.html
Copyright © 2020-2023  润新知