• jzoj6370. 【NOIP2019模拟2019.9.28】基础 fake 练习题


    Description

    装饰者坐在树荫下听着长者讲述以前的故事:
    大神 yk 非常喜欢树,便钦点班里的 n 个小蒟蒻站在一棵 n 个点以 1 为根的树上,并且每个点上恰好有 1 个小蒟蒻。
    大神 yk 非常喜欢 fake,尤其是 fake 比他弱的人。根据可靠消息,大神 yk 拟定了m 个假人计划,每个假人计划形如 fake 树上从点 u 到点 v 的简单路径上站的小蒟蒻。但大神 yk 不喜欢拐角,所以假人计划选择的简单路径的端点满足 v 在 1 到 u 的简单路径上或者 u 在 1 到 v 的简单路径上。
    每个小蒟蒻毕竟是人,忍耐是有限度的,站在 i 号点的小蒟蒻的忍耐值为 ci。当这个小蒟蒻被 fake 的次数超过 ci 后,这个小蒟蒻会非常地愤怒。
    大神 yk 可以从 m 个假人计划中选出任意多个执行,但是大神 yk 不想让任意一个小蒟蒻感到愤怒,因为这样会破坏友谊。
    装饰者听到这里,很好奇大神 yk 最多能实施多少假人计划。但是这个问题太简单了,装饰者秒掉了它。于是它被当成模拟赛的签到题扔你做。

    Input

    第一行有 2 个正整数 n, m。
    第二行有 n 个非负整数 c1, · · · , cn,描述小蒟蒻的忍耐值。
    接下来有 n n 1 行,每行两个正整数 u, v,描述树上的一条边。
    最后有 m 行,每行 2 个正整数 u, v 表示每个假人计划所选择的简单路径。

    Output

    仅一行,1 个整数,表示大神 yk 最多能实施的假人计划数。

    Sample Input

    5 3
    1 1 2 1 1
    1 2
    1 3
    3 4
    3 5
    1 4
    1 2
    3 5

    Sample Output

    2

    Data Constraint

    在这里插入图片描述

    赛时

    这题比赛的时候比较逗比。
    无脑直接想了个sb贪心。
    由于被T3T1搞崩心态了,这题以为又是一道省选+的题。
    然后就上了LCT
    打完我才发现我的贪心有点bug。
    然后转战可撤销堆。
    等我大致想到后,比赛已经结束了。

    我才不会告诉你可撤销堆依然是错的,但是应该可以水很多分,然鹅他是捆绑数据。

    题解

    也是贪心。
    直接在树上跑,每个点用线段树维护其上面节点的deep。
    然后每次如果小蒟蒻不能被fake后,就贪心把deep最小的几个删掉。
    然后线段树合并即可。

    标程

    #include <iostream>
    #include <cstring>
    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    #include <cctype>
    using namespace std;
    const int maxn=1000010;
    
    int n,m,a[maxn],fa[maxn],val[maxn],de[maxn],dep[maxn],root[maxn],x,y,zd,ans,ii[maxn];
    int tot,nex[maxn*2],las[maxn*2],tov[maxn*2];
    int tot1,nex1[maxn*2],las1[maxn*2],tov1[maxn*2];
    int sum[10*maxn],ls[10*maxn],rs[10*maxn],lazy[10*maxn],cnt;
    
    int insert(int x,int y)
    {
    	tot++;
    	tov[tot]=y;
    	nex[tot]=las[x];
    	las[x]=tot;
    }
    
    int insert1(int x,int y)
    {
    	tot1++;
    	tov1[tot1]=y;
    	nex1[tot1]=las1[x];
    	las1[x]=tot1;
    }
    
    
    void downlazy(int x)
    {
    	if (lazy[x]==1)
    	{
    		sum[ls[x]]=0;
    		sum[rs[x]]=0;
    		lazy[ls[x]]=1;
    		lazy[rs[x]]=1;
    		lazy[x]=0;
    	}
    }
    
    int merge(int x,int y)
    {
    	downlazy(x);
    	downlazy(y);
        if (x==0) return y;
        if (y==0) return x;
        int t=++cnt;
        sum[t]=sum[x]+sum[y];
        ls[t]=merge(ls[x],ls[y]);
        rs[t]=merge(rs[x],rs[y]);
        return t;
    }
    
    void modify(int x,int l,int r,int wz,int g)
    {
    	if (l==r)
    	{
    		sum[x]+=g; 
    	}	
    	else
    	{
    		downlazy(x);
    		int mid=(l+r)/2;
    		if (mid>=wz) 
    		{
    			if (ls[x]==0) ls[x]=++cnt;
    			modify(ls[x],l,mid,wz,g);
    		}
    		else 
    		{
    			if (rs[x]==0) rs[x]=++cnt;
    			modify(rs[x],mid+1,r,wz,g);
    		}
    		sum[x]=sum[ls[x]]+sum[rs[x]];
    	}
    } 
    
    void query(int x,int l,int r,int wz)
    {
    	if (l==r)
    	{
    		ans+=sum[x];
    		sum[x]=0;
    	}	
    	else
    	{
    		downlazy(x);
    		int mid=(l+r)/2;
    		if (mid>=wz) 
    		{
    			query(ls[x],l,mid,wz);
    		}
    		else 
    		{
    			query(rs[x],mid+1,r,wz);
    		}
    		sum[x]=sum[ls[x]]+sum[rs[x]];
    	}
    } 
    
    void clear(int x,int l,int r,int siz)
    {
    	if (l==r)
    	{
    		sum[x]-=siz;
    	}
    	else
    	{
    		downlazy(x);
    		int mid=(l+r)/2;
    		if (sum[ls[x]]<=siz)
    		{
    			siz-=sum[ls[x]];
    			sum[ls[x]]=0;
    			lazy[ls[x]]=1;
    			clear(rs[x],mid+1,r,siz);
    		}
    		else clear(ls[x],l,mid,siz);
    		sum[x]=sum[ls[x]]+sum[rs[x]];
    	}
    }
    
    void dfs(int x)
    {
    	zd=max(zd,dep[x]);
    	for (ii[x]=las[x];ii[x]>0;ii[x]=nex[ii[x]])
    	{
    		if (tov[ii[x]]!=fa[x])
    		{
    			fa[tov[ii[x]]]=x;
    			dep[tov[ii[x]]]=dep[x]+1;
    			dfs(tov[ii[x]]);
    		}
    	}
    }
    
    void getans(int x)
    {
    	root[x]=0;
    	for (ii[x]=las[x];ii[x]>0;ii[x]=nex[ii[x]])
    	{
    		if (tov[ii[x]]!=fa[x])
    		{
    			getans(tov[ii[x]]);
    			root[x]=merge(root[x],root[tov[ii[x]]]);
    		}
    	}
    	if (root[x]==0)
    	{
    		cnt++;
    		root[x]=cnt;
    	}
    	for (ii[x]=las1[x];ii[x]>0;ii[x]=nex1[ii[x]])
    	modify(root[x],1,zd,tov1[ii[x]],1);
    	int total=sum[root[x]]-a[x];
    	if (total>0)
    	{
    		clear(root[x],1,zd,total);
    	}
    	if (de[x]>0)
    	query(root[x],1,zd,dep[x]);
    }
    
    int main()
    {
    //	freopen("data.in","r",stdin);
    	freopen("fake.in","r",stdin);
    	freopen("fake.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    	}
    	for (int i=1;i<n;i++)
    	{
    		scanf("%d%d",&x,&y);
    		insert(x,y);
    		insert(y,x);
    	}
    	dep[1]=1;
    	dfs(1);
    	for (int i=1;i<=m;i++)
    	{
    		scanf("%d%d",&x,&y);
    		if (x==y)
    		{
    			int j=0;
    		}
    		if (dep[x]>dep[y])
    		{
    			swap(x,y);
    		}
    		de[x]++;
    		val[y]++;
    		insert1(y,dep[x]);
    	}
    	getans(1);
    	printf("%d
    ",ans);
    }
    
  • 相关阅读:
    GreenPlum 锁表以及解除锁定
    Postgresql 解决锁表
    Greenplum 查看连接与锁信息数据字典
    Greenplum 常用数据字典
    Linux 内核参数说明
    Greenplum 如何直连segment节点
    GreenPlum 数据备份与恢复
    unity 获取DontDestroyOnLoad的游戏对象
    scheduleOnce时出错,CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: 0 to 0"
    正比适配,留黑边
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11610377.html
Copyright © 2020-2023  润新知