题目大意

  给定一棵\(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. matplot绘图基本使用

    先看一个最简单的例子 import matplotlib.pyplot as plt plt.figure() plt.subplot(211) plt.plot([1,2,3], color=''r ...

  2. Django Rest framework基础使用之Request/Response

    1.Request restframework提供了一个Request对象(rest_framework.request.Request) Request对象继承了Django默认的HttpReque ...

  3. 二十:让行内元素在div中垂直居中

    (1)使用display:table-cell配合vertical-align:center(淘宝也是这样用的) <div class="method4"> <s ...

  4. MySQL的log_bin和sql_log_bin 的区别

    利用二进制还原数据库的时候,突然有点纠结,log_bin和sql_log_bin有什么区别呢?行吧,搜搜,结合自己的经验,简单说一下.log_bin:二进制日志. 在 mysql 启动时,通过命令行或 ...

  5. H5 54-清空默认边距

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. Django之路由分发反向解析

    Django路由分发|反向解析 当一个Django中有多个app时,路由会有很多,将这些路由都写在与项目同名的文件夹下就会显得很多,很乱.并且在协同开发的时候容易出现相同的命名,当项目合并后就会出现路 ...

  7. Django组件之认证系统

      Django自带的用户认证 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册.用户登录.用户认证.注销.修改密码等功能,这还真是个麻烦的事情呢. Dja ...

  8. spring datasource jdbc 密码 加解密

    spring datasource 密码加密后运行时解密的解决办法 - 一号门-程序员的工作,程序员的生活(java,python,delphi实战)http://www.yihaomen.com/a ...

  9. ubuntu使用squid搭建代理

    安装squid //检查是否安装squid which squid // apt update sudo apt install squid 配置squid的配置文件squid.conf //备份sq ...

  10. ShowDoc上手

    ShowDoc是什么 每当接手一个他人开发好的模块或者项目,看着那些没有写注释的代码,我们都无比抓狂.文档呢?!文档呢?!Show me the doc !! 程序员都很希望别人能写技术文档,而自己却 ...