2019雅礼集训 D8T3 union [主席树]
Posted p-b-p-b
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019雅礼集训 D8T3 union [主席树]相关的知识,希望对你有一定的参考价值。
题目描述:
样例:
input:
12
1 1 1 4 1 1 5 2 8 1 6
output:
3
6
11
6
7
6
11
8
11
11
11
11
数据范围与约定:
一道比较正常的主席树题
我才不会告诉你我考场上写了树链剖分+线段树+set还写挂了呢
容易发现我们只需要把删去每个节点后的联通块最大值(mx_1),次大值(mx_2)和最小值(mn)求出来,然后在(mx_1)里面抠下来一块大小为(v)的子树连到(mn?)里即可。
其中最优的(v_0?)满足(mx_1-v_0=v_0+mn?)。
然而能不能刚好抠下来大小为(v)的一块还是个问题。
假设当前要求答案的点是(x?),对于不是(x?)的祖先的节点(y?),把它的父节点改一下就会使(size_y?)个点改变位置;而对于(x?)的某一个祖先(z?),改变的则是(size_z-size_x?)。
所以我们需要分两种情况进行讨论。
建两棵主席树:第一棵建在(dfs)序上,以便快速统计子树信息;第二棵建在树上,以便快速统计链的信息。两棵主席树均是以(size)为关键字的值域线段树。
然后分类讨论:
当(mx_1)是(x)的某一个儿子的子树时:直接用第一棵主席树二分出最优的v即可。
当(mx_1)是整棵树除去(x)的子树时:
1:在(x)到(1)的链上:查询这一条链,注意加上和减去(size_x)。
2:不在链上:用整棵树减去x的子树再减去(x)到(1)的链,然后查询,注意加上和减去(size_x)。
最后还要特判一下1只有一个儿子时输出(n-1?)
个人认为两棵不同的主席树相减还是非常骚的,第一次见到。
代码:
#include<bits/stdc++.h>
namespace my_std{
using namespace std;
#define mod 998244353
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define sz 100100
typedef long long ll;
template<typename T>
inline void read(T& t)
{
t=0;char f=0,ch=getchar();
double d=0.1;
while(ch>‘9‘||ch<‘0‘) f|=(ch==‘-‘),ch=getchar();
while(ch<=‘9‘&&ch>=‘0‘) t=t*10+ch-48,ch=getchar();
if(ch==‘.‘)
{
ch=getchar();
while(ch<=‘9‘&&ch>=‘0‘) t+=d*(ch^48),d*=0.1,ch=getchar();
}
t=(f?-t:t);
}
template<typename T,typename... Args>
inline void read(T& t,Args&... args){read(t); read(args...);}
void file()
{
freopen("traffic.in","r",stdin);
freopen("traffic.out","w",stdout);
}
inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
int n;
struct hh{int t,nxt;}edge[sz<<1];
int head[sz],ecnt;
void make_edge(int f,int t){edge[++ecnt]=(hh){t,head[f]};head[f]=ecnt;}
#define Tree sz*60
int sum[Tree],ls[Tree],rs[Tree],cnt;
int rt1[sz],rt2[sz];
void insert(int &k,int pre,int l,int r,int x)
{
k=++cnt;sum[k]=sum[pre]+1;ls[k]=ls[pre],rs[k]=rs[pre];
if (l==r) return;
int mid=(l+r)>>1;
if (x<=mid) insert(ls[k],ls[pre],l,mid,x);
else insert(rs[k],rs[pre],mid+1,r,x);
}
#define lson ls[a],ls[b],ls[c],ls[d],l,mid
#define rson rs[a],rs[b],rs[c],rs[d],mid+1,r
int queryL(int a,int b,int c,int d,int l,int r,int x)
{
if (l>x) return -1;
if (sum[a]+sum[b]-sum[c]-sum[d]==0) return -1;
if (l==r) return l;
int mid=(l+r)>>1;
int ret=queryL(rson,x);
return ret==-1?queryL(lson,x):ret;
}
int queryR(int a,int b,int c,int d,int l,int r,int x)
{
if (r<x) return -1;
if (sum[a]+sum[b]-sum[c]-sum[d]==0) return -1;
if (l==r) return l;
int mid=(l+r)>>1;
int ret=queryR(lson,x);
return ret==-1?queryR(rson,x):ret;
}
//queryL & queryR 查询与x最接近的size
#undef lson
#undef rson
#undef Tree
#define v edge[i].t
int dfn[sz],low[sz],pre[sz],fa[sz],size[sz],T;
void dfs(int x)
{
size[x]=1;pre[dfn[x]=++T]=x;
go(x) dfs(v),size[x]+=size[v];
low[x]=T;
}
void build1(){rep(i,1,n) insert(rt1[i],rt1[i-1],1,n,size[pre[i]]);}
void build2(int x)
{
insert(rt2[x],rt2[fa[x]],1,n,size[x]);
go(x) build2(v);
}
inline int max(int x,int y,int z){return max({x,y,z});}
void solve(int x)
{
int mn=n,mx1=0,mx2=0;
go(x)
{
if (size[v]>=mx1) mx2=mx1,mx1=size[v];
else mx2=max(mx2,size[v]);
mn=min(mn,size[v]);
}
if (x!=1)
{
int t=n-size[x];
if (t>mx1) mx2=mx1,mx1=t;
else mx2=max(mx2,t);
mn=min(mn,t);
}
int val=(mx1-mn)/2;
int ans=n;
#define update(v) ans=min(ans,v)
if (mx1==n-size[x]&&x!=1)
{
int v1=queryL(rt2[x],0,0,0,1,n,val+size[x]);
int v2=queryR(rt2[x],0,0,0,1,n,val+size[x]);
if (v1!=-1) v1-=size[x],update(max(mx2,mx1-v1,mn+v1));
if (v2!=-1) v2-=size[x],update(max(mx2,mx1-v2,mn+v2));
v1=queryL(rt1[n],rt1[dfn[x]],rt1[low[x]],rt2[x],1,n,val);
v2=queryR(rt1[n],rt1[dfn[x]],rt1[low[x]],rt2[x],1,n,val);
if (v1!=-1) update(max(mx2,mx1-v1,mn+v1));
if (v2!=-1) update(max(mx2,mx1-v2,mn+v2));
}
go(x) if (size[v]==mx1)
{
int v1=queryL(rt1[low[v]],0,rt1[dfn[v]-1],0,1,n,val);
int v2=queryR(rt1[low[v]],0,rt1[dfn[v]-1],0,1,n,val);
if (v1!=-1) update(max(mx2,mx1-v1,mn+v1));
if (v2!=-1) update(max(mx2,mx1-v2,mn+v2));
}
#undef update
if (x==1&&mn==mx1) ans=n-1;
printf("%d
",ans);
}
#undef v
int main()
{
file();
read(n);
rep(i,2,n) read(fa[i]),make_edge(fa[i],i);
dfs(1);build1();build2(1);
rep(i,1,n) solve(i);
}
以上是关于2019雅礼集训 D8T3 union [主席树]的主要内容,如果未能解决你的问题,请参考以下文章
2019雅礼集训 D7T2 subsequence [DP,平衡树]
2019牛客国庆集训派对day2 C.Just h-index(主席树)