题目大意

  给定一棵\(n\)个点的树,对于树上每个结点,将它删去,然后可以将得到的森林中任意一个点与其父亲断开并连接到另一颗树上,对每一个点求出森林中所有树\(size\)最大值的最小值。

  \(n\leq 100000\)

题解

  首先用DFS序+可持久化线段树求出删掉这个点后剩下的联通块的大小的最大值\(max\)、次大值\(sec\)、最小值\(min\)。这里要维护两棵可持久化线段树,一棵是DFS序前缀的,一棵是从根到每个点的。

  那么肯定是在最大的连通块上切下一块接到最小的连通块上。

  假设切下的大小为\(x\),那么答案是\(\max(max-x,min+x,sec)\)。这个的图像是带一个向下的尖角的,这个尖角的位置为\(\frac{max+min}{2}\)。所以我们要切下来的\(x\)就是\(\frac{max-min}{2}\)。我们只需要在对应的可持久化线段树上找这个值的前驱和后继并统计答案。

  切下来的部分有三种可能:

   1.在\(x\)的子树内,可以直接统计答案

   2.在\(x\)的子树外且不包含\(x\)到根的点,可以直接统计答案

   3.在\(x\)的子树外切包含根到\(x\)的点,查询到的子树大小要减掉\(size_x\)

  时间复杂度:\(O(n\log n)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<list>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
namespace sgt
{
int rt1[100010];
int rt2[100010];
struct node
{
int lc,rc;
int s;
node()
{
lc=rc=s=0;
}
};
node a[10000010];
int cnt=0;
int insert(int p1,int x,int l,int r)
{
int p=++cnt;
a[p]=a[p1];
a[p].s++;
if(l==r)
return p;
int mid=(l+r)>>1;
if(x<=mid)
a[p].lc=insert(a[p].lc,x,l,mid);
else
a[p].rc=insert(a[p].rc,x,mid+1,r);
return p;
}
int suf(int p1,int p2,int p3,int p4,int x,int l,int r)//p1+p3-p2-p4
{
int s=a[p1].s+a[p3].s-a[p4].s-a[p2].s;
if(!s)
return 0x3fffffff;
if(l==r)
return l;
int mid=(l+r)>>1;
int ls=a[a[p1].lc].s+a[a[p3].lc].s-a[a[p4].lc].s-a[a[p2].lc].s;
if(x<=mid&&ls)
{
int lans=suf(a[p1].lc,a[p2].lc,a[p3].lc,a[p4].lc,x,l,mid);
if(lans!=0x3fffffff)
return lans;
}
return suf(a[p1].rc,a[p2].rc,a[p3].rc,a[p4].rc,x,mid+1,r);
}
int pre(int p1,int p2,int p3,int p4,int x,int l,int r)
{
int s=a[p1].s+a[p3].s-a[p4].s-a[p2].s;
if(!s)
return 0;
if(l==r)
return l;
int mid=(l+r)>>1;
int rs=a[a[p1].rc].s+a[a[p3].rc].s-a[a[p4].rc].s-a[a[p2].rc].s;
if(x>mid&&rs)
{
int rans=pre(a[p1].rc,a[p2].rc,a[p3].rc,a[p4].rc,x,mid+1,r);
if(rans)
return rans;
}
return pre(a[p1].lc,a[p2].lc,a[p3].lc,a[p4].lc,x,l,mid);
}
int getmax(int p1,int p2,int p3,int p4,int l,int r)
{
int s=a[p1].s+a[p3].s-a[p4].s-a[p2].s;
if(!s)
return 0;
if(l==r)
return l;
int mid=(l+r)>>1;
int rs=a[a[p1].rc].s+a[a[p3].rc].s-a[a[p4].rc].s-a[a[p2].rc].s;
if(rs)
return getmax(a[p1].rc,a[p2].rc,a[p3].rc,a[p4].rc,mid+1,r);
return getmax(a[p1].lc,a[p2].lc,a[p3].lc,a[p4].lc,l,mid);
}
int getmin(int p1,int p2,int p3,int p4,int l,int r)
{
int s=a[p1].s+a[p3].s-a[p4].s-a[p2].s;
if(!s)
return 0x3fffffff;
if(l==r)
return l;
int mid=(l+r)>>1;
int ls=a[a[p1].lc].s+a[a[p3].lc].s-a[a[p4].lc].s-a[a[p2].lc].s;
if(ls)
return getmin(a[p1].lc,a[p2].lc,a[p3].lc,a[p4].lc,l,mid);
return getmin(a[p1].rc,a[p2].rc,a[p3].rc,a[p4].rc,mid+1,r);
}
}
using sgt::rt1;
using sgt::rt2;
using sgt::insert;
using sgt::suf;
using sgt::pre;
using sgt::getmax;
using sgt::getmin;
list<int> l[100010];
int f[100010];
int st[100010];
int ed[100010];
int s[100010];
int w[100010];
int ti;
int n;
void dfs1(int x)
{
st[x]=++ti;
w[ti]=x;
s[x]=1;
for(auto v:l[x])
{
dfs1(v);
s[x]+=s[v];
}
ed[x]=ti;
}
int update(int &a,int &b,int &c)
{
if(c>=a)
{
b=a;
a=c;
return 1;
}
else
{
b=max(b,c);
return 2;
}
return 0;
}
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
scanf("%d",&n);
int rt,x,y;
int i;
for(i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
if(x)
{
l[x].push_back(y);
f[y]=x;
}
else
rt=y;
}
dfs1(rt);
for(i=1;i<=n;i++)
{
x=w[i];
rt2[x]=insert(rt2[f[x]],s[x],1,n);
rt1[i]=insert(rt1[i-1],s[x],1,n);
}
for(i=1;i<=n;i++)
{
int mx=0,sec=0,mi=0x7fffffff;
int s1,s2,s3,s4,ans;
int mv; for(auto v:l[i])
{
s1=s[v];
if(update(mx,sec,s1)==1)
{
s4=1;
mv=v;
}
mi=min(mi,s1);
}
s1=n-s[i];
if(s1)
{
if(update(mx,sec,s1)==1)
s4=2;
mi=min(mi,s1);
}
ans=0x7fffffff;
int mid=(mi+mx+1)>>1;
int s5=mx-mid;
if(i==1)
int xxx=1;
ans=min(ans,mx);
if(s4==1)
{
s1=pre(rt1[ed[mv]],rt1[st[mv]-1],0,0,s5,1,n);
s2=suf(rt1[ed[mv]],rt1[st[mv]-1],0,0,s5,1,n);
ans=min(ans,max(sec,max(mi+s1,mx-s1)));
ans=min(ans,max(sec,max(mi+s2,mx-s2)));
}
else if(s4==2)
{
s1=pre(rt2[f[i]],0,0,0,s5+s[i],1,n);
s2=suf(rt2[f[i]],0,0,0,s5+s[i],1,n);
if(s1)
s1-=s[i];
if(s2!=0x3fffffff)
s2-=s[i];
ans=min(ans,max(sec,max(mi+s1,mx-s1)));
ans=min(ans,max(sec,max(mi+s2,mx-s2)));
s1=pre(rt1[st[i]-1],rt1[ed[i]],rt1[n],rt2[f[i]],s5,1,n);
s2=suf(rt1[st[i]-1],rt1[ed[i]],rt1[n],rt2[f[i]],s5,1,n);
ans=min(ans,max(sec,max(mi+s1,mx-s1)));
ans=min(ans,max(sec,max(mi+s2,mx-s2)));
}
printf("%d\n",ans);
}
return 0;
}

【CF768G】The Winds of Winter 可持久化线段树 DFS序的更多相关文章

  1. Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

    题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s   内存限制:512.0MB    总提交次数:196   AC次数:65   平均分: ...

  2. BZOJ3653谈笑风生——可持久化线段树+dfs序

    题目描述 设T 为一棵有根树,我们做如下的定义: ? 设a和b为T 中的两个不同节点.如果a是b的祖先,那么称“a比b不知道 高明到哪里去了”. ? 设a 和 b 为 T 中的两个不同节点.如果 a ...

  3. BZOJ_3252_攻略_线段树+dfs序

    BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...

  4. 【XSY2534】【BZOJ4817】树点涂色 LCT 倍增 线段树 dfs序

    题目大意 ​ Bob有一棵\(n\)个点的有根树,其中\(1\)号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜 ...

  5. 【bzoj4817】树点涂色 LCT+线段树+dfs序

    Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...

  6. S - Query on a tree HDU - 3804 线段树+dfs序

    S - Query on a tree HDU - 3804   离散化+权值线段树 题目大意:给你一棵树,让你求这棵树上询问的点到根节点直接最大小于等于val的长度. 这个题目和之前写的那个给你一棵 ...

  7. HDU 5692 线段树+dfs序

    Snacks Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  8. 【BZOJ-3779】重组病毒 LinkCutTree + 线段树 + DFS序

    3779: 重组病毒 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 224  Solved: 95[Submit][Status][Discuss] ...

  9. 【BZOJ-3306】树 线段树 + DFS序

    3306: 树 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 792  Solved: 262[Submit][Status][Discuss] De ...

随机推荐

  1. 解决CPC撰写文档报错问题“无法获取“AxforApplication”控件的窗口句柄。不支持无窗口的 ActiveX 控件”

    最近公司需要把官方CPC电子申请移植到项目中,在移植完成后,撰写文档总是出现“无法获取“AxforApplication”控件的窗口句柄.不支持无窗口的 ActiveX 控件”,另楼主头疼很久,网上寥 ...

  2. H5 文字属性

    03-文字属性 我是文字 我是文字 abc我是段落 <!DOCTYPE html> <html lang="en"> <head> <me ...

  3. codeforces#1097 D. Makoto and a Blackboard(dp+期望)

    题意:现在有一个数写在黑板上,它以等概率转化为它的一个约数,可以是1,问经过k次转化后这个数的期望值 题解:如果这个数是一个素数的n次方,那么显然可以用动态规划来求这个数的答案,否则的话,就对每个素因 ...

  4. XGBoost模型的参数调优

    XGBoost算法在实际运行的过程中,可以通过以下要点进行参数调优: (1)添加正则项: 在模型参数中添加正则项,或加大正则项的惩罚力度,即通过调整加权参数,从而避免模型出现过拟合的情况. (2)控制 ...

  5. openstack-KVM-vCPU

    一.KVM基础功能 (1)支持 硬件支持 VT-x VT-d 系统支持 kernel > 3.5 (2)计算机系统的子系统 CPU 处理器 Memory 内存 Storage 存储 Networ ...

  6. BAT (中国互联网公司三巨头)

    BAT,B=百度.A=阿里巴巴.T=腾讯,是中国互联网公司百度公司(Baidu).阿里巴巴集团(Alibaba).腾讯公司(Tencent)三大互联网公司首字母的缩写.百度总部在北京.阿里巴巴总部在浙 ...

  7. CentOS 7 安装配置带用户认证的squid代理服务器

    这里只简述搭建一个带用户认证的普通代理 一.安装 安装过程十分简便,只需要安装一下squid,一条命令搞定 yum install squid rpm -qa | grep squid squid-- ...

  8. C#设计模式之5:简单工厂和工厂方法模式

    工厂模式包含三种,简单工厂模式,工厂方法模式,抽象工厂模式.这三种都是解决了一个问题,那就是对象的创建问题.他们的职责就是将对象的创建和对象的使用分离开来. 当我们创建对象的时候,总是会new一个对象 ...

  9. java语句中的重定向函数

    重定向后面就不能转发了,所以return null

  10. CSS3 Flexbox轻巧实现元素的水平居中和垂直居中

    CSS3 Flexbox轻松实现元素的水平居中和垂直居中 网上有很多关于Flex的教程,对于Flex的叫法也不一,有的叫Flexbox,有的叫Flex,其实这两种叫法都没有错,只是Flexbox旧一点 ...