zoukankan      html  css  js  c++  java
  • 题解「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;
    }
    
  • 相关阅读:
    QTP模拟鼠标和键盘事件整理
    Linux 入门常用命令 — 改变文件或目录的访问权限
    做一个有品质的男人
    Linux下.tar .gz .tgz .bz2 .bz等解、压包命令详解
    全面整理CentOS系统使用中文
    MSDN宝藏库中,初学者应该看的东西【整理的很辛苦哦】
    IIS 7.5版本中一些诡异问题的解决方案
    老生常谈ASP.NET中的Cookies,罗列读写Cookies的方法
    分享3段平时很实用的微代码,高手莫喷
    SQL 2005中的临时表
  • 原文地址:https://www.cnblogs.com/syc233/p/14051999.html
Copyright © 2011-2022 走看看