zoukankan      html  css  js  c++  java
  • Day 11.20模拟赛游记

    又是爆零的一天!


    没写出的题就写写知识点吧:

    • T1:线段树合并

    • T3:kruskal重构树

    • T4:FFT


    T2

    题目大意:一棵树,对于每一个(i),求有多少个(j)(i)的联系节点,(j)满足(forall k(j<kle i))都是(j)的子孙节点。

    题目挺简单,但考场上完全想错方向,对于(j)的右边最多可以作为那些(i)的联系节点,易证这些(i)一定是连续的,而且紧挨着(j),因为一旦有一个不是(j)的子孙节点,后面的就都不会是(j)的联系节点了。所以我们就可以二分这个右端点,用(dfs)序或许是一个不错的选择。

    众所周知,只要(i)满足(dfn_jle dfn_ile dfn_j+size_j-1)(i)就在(j)的子树内,所以用(st)表维护一个(dfn)的最大值和最小值,卡卡常就可以(O(nlogn))解决此题。

    #include<bits/stdc++.h>
    #define re register
    using namespace std;
    const int N=2200005;
    inline int read()
    {
    	re int x=0,f=1;
    	re char ch=getchar();
    	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') f*=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
    	return x*f;
    }
    void print(int x)
    {
    	if(x>9) print(x/10);
    	putchar(x%10^48);
    }
    inline int min(int x,int y){return x<y?x:y;}
    inline int max(int x,int y){return x>y?x:y;}
    struct edge{int v,net;}e[N];
    int n,cnt,hd[N],dfn[N],siz[N],tot,mi[N][22],ma[N][22],sum[N];
    inline void add(int u,int v){e[++cnt].v=v,e[cnt].net=hd[u],hd[u]=cnt;}
    void first(int u)
    {
    	dfn[u]=++tot,siz[u]=1;
    	for(re int i=hd[u],v;i;i=e[i].net)
    	{
    		v=e[i].v;
    		first(v);
    		siz[u]+=siz[v];
    	}
    	return ;
    }
    int main()
    {
    	freopen("ancestor.in","r",stdin);
    	freopen("ancestor.out","w",stdout);
    	n=read();
    	for(re int i=2;i<=n;i++) add(read(),i);
    	first(1),ma[n][0]=mi[n][0]=dfn[n];
    	for(re int i=n-1;i>0;i--)
    	{
    		mi[i][0]=min(dfn[i],dfn[i+1]);
    		ma[i][0]=max(dfn[i],dfn[i+1]);
    		for(re int j=1;j<22;j++)
    		{
    			if(i+(1<<j)>n) break;
    			mi[i][j]=min(mi[i][j-1],mi[i+(1<<j-1)][j-1]);
    			ma[i][j]=max(ma[i][j-1],ma[i+(1<<j-1)][j-1]);
    		}
    	}
    	for(re int i=1,mid;i<=n;i++)
    	{
    		mid=i;
    		for(re int j=21;j>=0;j--)
    			if(mid+(1<<j)<=n&&ma[mid][j]<=dfn[i]+siz[i]-1&&mi[mid][j]>=dfn[i]) mid=mid+(1<<j);
    		sum[i]++,sum[mid+1]--;
    	}
    	for(re int i=1;i<=n;i++) sum[i]+=sum[i-1];
    	for(re int i=1;i<=n;i++) print(sum[i]),putchar('
    ');
    	return 0;
    }
    
  • 相关阅读:
    Centos系统通过tar.gz包安装Mysql5.7
    每日编程系列——洗牌
    每日编程系列——硬币找零
    每日编程系列———计算糖果
    每日编程系列———买苹果
    每日编程系列———最大奇约数
    Java包装类缓存
    每日编程系列——数字翻转
    Java自动装箱和拆箱
    Java中日志框架使用
  • 原文地址:https://www.cnblogs.com/jkzcr01-QAQ/p/14014501.html
Copyright © 2011-2022 走看看