zoukankan      html  css  js  c++  java
  • 【2020.11.30提高组模拟】剪辣椒(chilli) 题解

    【2020.11.30提高组模拟】剪辣椒(chilli) 题解

    题意简述

    给你一棵树,删去两条边,使得形成的三棵新树的大小极差最小化。求最小极差.

    (3le nle 200,000).

    Solution

    假设根为(1).

    删去的点意为这个点到其父亲的连边被删了,关系指一个点是另一个点的祖先,(size_x)为以(x)为根的子树大小,(a,b,c)是三棵新子树的大小。

    答案即为

    [ans=max(a,b,c)-min(a,b,c) ]

    那么只会有两种情况:

    被删去的点有关系

    不妨设(x)(y)的祖先

    [a=size_y,b=size_x-size_y,c=n-size_x ]

    被删去的点无关系

    [a=size_x,b=size_y,c=n-size_x-size_y ]

    显然这里就有一种比较暴力的方法了,时间复杂度(O(n^2))

    考虑优化。

    optimization

    (dfs)中,我们维护两个(set:A,B)

    当进入点(x)时,把(size_x)放入(A)中;

    当走出点(x)时,把(size_x)(A)中删除并放入(B)中;

    这样(A)里的元素就是(x)的直接祖先,(B)中是与(x)无关系的点(不需要考虑到还没有访问到的点,因为反过来会遍历到的)

    接下来每到一个点(x),我们继续考虑两种情况:

    被删去的点有关系

    假如我们要删去点(x),另一个被删去的点为y应使得(n-size_y)(size_y-size_x)这两个子树的大小最平均,即(n-size_y=size_y-size_xRightarrow 2size_y=n+size_x)

    image-20201130165920582

    我承认我图很丑,我谢罪……

    那么我们就去(A)中找一个值接近上面(size_y)的值并更新答案。

    当然,不一定会有正好相等的,应该用lower_bound()后在让指针iter--,进行两次判断。

    被删去的点无关系

    同理假如我们要删去点(x)和与它无关系的点(y),就要使得(size_y)(n-size_x-size_y)这两个值最相近,即(size_y=n-size_x-size_yRightarrow 2size_y=n-size_x)

    image-20201130171004060

    我承认我图很丑,我再次谢罪……

    那么我们就去(B)中找一个值接近上面(size_y)的值并更新答案。

    Code

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<map>
    #include<set>
    #include<queue>
    #include<vector>
    #define IL inline
    #define re register
    #define LL long long
    #define ULL unsigned long long
    #ifdef TH
    #define debug printf("Now is %d
    ",__LINE__);
    #else
    #define debug
    #endif
    using namespace std;
    
    template<class T>inline void read(T&x)
    {
    	char ch=getchar();
    	int fu;
    	while(!isdigit(ch)&&ch!='-') ch=getchar();
    	if(ch=='-') fu=-1,ch=getchar();
    	x=ch-'0';ch=getchar();
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	x*=fu;
    }
    inline int read()
    {
    	int x=0,fu=1;
    	char ch=getchar();
    	while(!isdigit(ch)&&ch!='-') ch=getchar();
    	if(ch=='-') fu=-1,ch=getchar();
    	x=ch-'0';ch=getchar();
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return x*fu;
    }
    int G[55];
    template<class T>inline void write(T x)
    {
    	int g=0;
    	if(x<0) x=-x,putchar('-');
    	do{G[++g]=x%10;x/=10;}while(x);
    	for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar('
    ');
    }
    int n;
    int ans=100000000;
    set<int>A,B;
    int sze[200010];
    int head[400010],ver[400010],nxt[400010];
    int cnt;
    void insert(int x,int y)
    {
    	nxt[++cnt]=head[x];
    	ver[cnt]=y;
    	head[x]=cnt;
    	
    	nxt[++cnt]=head[y];
    	ver[cnt]=x;
    	head[y]=cnt;
    }
    void dfs1(int x,int fa)
    {
    	sze[x]=1;
    	for(int i=head[x];i;i=nxt[i])
    	{
    		if(ver[i]!=fa)
    		{
    			dfs1(ver[i],x);
    			sze[x]+=sze[ver[i]];
    		}
    	}
    }
    IL void upd(int x,int y,int z)
    {
    	ans=min(ans,max({x,y,z})-min({x,y,z}));
    }
    void dfs2(int x,int fa)
    {
    //	cout<<sze[x]<<endl;
    	A.insert(sze[x]);
    	set<int>::iterator iter;
    	iter=A.upper_bound((sze[x]+n)/2);
    	if(iter!=A.end())
    	{
    		upd(sze[x],*iter-sze[x],n-*iter);
    	}
    	if(iter!=A.begin())
    	{
    		iter--;
    		upd(sze[x],*iter-sze[x],n-*iter);
    	}
    	iter=B.upper_bound((n-sze[x])/2);
    	if(iter!=B.end())
    	{
    		upd(sze[x],*iter,n-sze[x]-*iter);
    	}
    	if(iter!=B.begin())
    	{
    		iter--;
    		upd(sze[x],*iter,n-sze[x]-*iter);
    	}
    	for(int i=head[x];i;i=nxt[i])
    	{
    		if(ver[i]!=fa)
    		{
    			dfs2(ver[i],x);
    		}
    	}
    	A.erase(sze[x]);
    	B.insert(sze[x]);
    }
    int main()
    {
    //	freopen("chilli.in","r",stdin);
    //	freopen("chilli.out","w",stdout);
    	n=read();
    	for(int i=1;i<n;i++) insert(read(),read());
    	dfs1(1,0);
    	dfs2(1,0);
    	cout<<ans;
    	return 0;
    }
    

    End

    一次性写完代码运行一下,没仔细看就以为自己WA了就来写Solution。写完Solution准备来Debug,写完的Debug语句再运行发现代码是对的!Woc泪目!


    绝了,(std)是老外写的吧,全是c++11auto啥的

    所以我也用了初始化列表+max(lists)

    嘿嘿,还挺方便的呢


    我在跑操的时候突然发现,这道题有些平衡树的思想。(而不是把(set)当成离散化bool数组来用)

    不断的插入值,删除值,求前驱后继……不就是平衡树嘛?

    看来我需要加强模型转化能力。

  • 相关阅读:
    vue-fullcalendar插件
    iframe 父框架调用子框架的函数
    关于调试的一点感想
    hdfs 删除和新增节点
    hadoop yarn 实战错误汇总
    Ganglia 安装 No package 'ck' found
    storm on yarn(CDH5) 部署笔记
    spark on yarn 安装笔记
    storm on yarn安装时 提交到yarn失败 failed
    yarn storm spark
  • 原文地址:https://www.cnblogs.com/send-off-a-friend/p/14062461.html
Copyright © 2011-2022 走看看