zoukankan      html  css  js  c++  java
  • 7376. 【2021.11.11NOIP提高组联考】超级加倍

    Description

    给定一棵树。

    我们认为一条从 (x ightarrow y) 的简单路径是好的,当且仅当路径上的点中编号最小的是 (x) ,最大的是 (y)

    请求出好的简单路径条数。

    (nle 2 imes 10^6)

    Solution

    编号最小和编号最大,是本题的关键。

    考虑能不能构造出这样的树,使得新的树中任意两点 ((u,v))(lca) 就是原来的树中 ((u,v)) 之间的最小/大值。

    这就令人想起了 kruskal 重构树,似乎跟这个性质十分类似。

    从大到小枚举编号( (x)),同时枚举该点连出去的边,若某条边连向的点((y))已经被加入新树中,那么就将新树中 (y) 的祖先的父亲记作 (x)。这可以通过并查集来实现。

    通过以上的操作,我们成功达成了我们的目的,现在想一下怎么用这个造出来的树。

    注意到我们建了两棵树,那么就可以发现,若原树中 ((x,y)) 是符合要求的,当且仅当在一棵树中 (x)(y) 的祖先,并且在另一棵树中,(y)(x) 的祖先。

    统计答案呢,我们可以先求出一棵树的 dfs 序。然后遍历另一棵树,回溯某点的时候将他的子树全部打上标记。那么一个点的答案就是打了多少个标记。

    注意到标记可能会由父亲那一边打过来,因此我们可以在遍历到这个点的时候记录值,回溯的时候再记录一次值,两次值之差才是真正的,由儿子产生的贡献。

    打标记显然是可以通过数据结构来完成的,我一开始打了线段树,但被卡常了,后来调成了树状数组才把这题切掉。

    Code

    #include<cstdio>
    #define N 2000005
    #define ll long long
    using namespace std;
    struct node
    {
    	int to,next,head;
    }a[N<<1],tree1[N<<1],tree2[N<<1];
    int n,x,tot,num1,num2,dnum,f[N],dfn[N],size[N],c[N];
    ll ans;
    int lowbit(int x) {return x&(-x);}
    void add(int x,int y)
    {
    	a[++tot].to=y;
    	a[tot].next=a[x].head;
    	a[x].head=tot;
    }
    void add1(int x,int y)
    {
    	tree1[++num1].to=y;
    	tree1[num1].next=tree1[x].head;
    	tree1[x].head=num1;
    }
    void add2(int x,int y)
    {
    	tree2[++num2].to=y;
    	tree2[num2].next=tree2[x].head;
    	tree2[x].head=num2;
    }
    int find(int x)
    {
    	if (f[x]!=x) f[x]=find(f[x]);
    	return f[x];
    }
    void modify(int x,int v)
    {
    	for (int i=x;i<=n;i+=lowbit(i))
    		c[i]+=v;	
    }
    ll query(int x)
    {
    	ll res=0;
    	for(int i=x;i;i-=lowbit(i))
    		res+=c[i];
    	return res;
    }
    void dfs1(int now,int fa)
    {
    	dfn[now]=++dnum;
    	size[now]=1;
    	for (int i=tree1[now].head;i;i=tree1[i].next)
    	{
    		int v=tree1[i].to;
    		if (v==fa) continue;
    		dfs1(v,now);
    		size[now]+=size[v];
    	}
    }
    void dfs2(int now,int fa)
    {
    	ll sum1=query(dfn[now]);
    	for (int i=tree2[now].head;i;i=tree2[i].next)
    	{
    		int v=tree2[i].to;
    		if (v==fa) continue;
    		dfs2(v,now);
    	}
    	ll sum2=query(dfn[now]);
    	ans+=sum2-sum1;
    	modify(dfn[now],1);modify(dfn[now]+size[now],-1);
    }
    int main()
    {
    	freopen("charity.in","r",stdin);
    	freopen("charity.out","w",stdout);
    	scanf("%d",&n);
    	for (int i=1;i<=n;++i)
    	{
    		scanf("%d",&x);
    		if (i!=1) add(x,i),add(i,x);
    	}
    	for (int i=1;i<=n;++i)
    		f[i]=i;
    	for (int i=n;i>=1;--i)
    	{
    		for (int j=a[i].head;j;j=a[j].next)
    		{
    			int v=a[j].to;
    			if (v>i)
    			{
    				int xf=find(v),yf=find(i);
    				f[xf]=yf;
    				add1(yf,xf);add1(xf,yf);
    			}
    		}
    	}
    	for (int i=1;i<=n;++i)
    		f[i]=i;
    	for (int i=1;i<=n;++i)
    	{
    		for (int j=a[i].head;j;j=a[j].next)
    		{
    			int v=a[j].to;
    			if (v<i)
    			{
    				int xf=find(v),yf=find(i);
    				f[xf]=yf;
    				add2(yf,xf);add2(xf,yf);
    			}
    		}
    	}
    	dfs1(1,0);
    	dfs2(n,0);
    	printf("%lld
    ",ans);
    	return 0;
    } 
    

    如果想看线段树代码的:
    传送门

  • 相关阅读:
    [Paper Review]Distilling the Knowledge in a Neural Network,2015
    Taylor Series and Gradient Descent
    Regularization from Large Wights Perspective
    Generative Model vs Discriminative Model
    State Function Approximation: Linear Function
    Temporal-Difference Control: SARSA and Q-Learning
    php扩展(centos+php7.2)---Composer: The requested PHP extension ext-intl * is missing from your system
    docker常用命令
    cURL error 60: SSL certificate problem: unable to get local issuer certificate
    【Magento 2学习】
  • 原文地址:https://www.cnblogs.com/Livingston/p/15542273.html
Copyright © 2011-2022 走看看