• YbtOJ#662交通运输【线段树合并,树状数组】


    正题

    题目链接:http://www.ybtoj.com.cn/contest/122/problem/2


    题目大意

    给出\(n\)个点的一棵有根树,对于每个\(x\)求,删除点\(x\)后修改某个点的父节点(修改前该点必须有父节点)后最小化最大联通块大小。


    解题思路

    删掉一个点后肯定是最大的那个联通块分一个子树给最小的那个联通块。
    \(maxs\)表示最大的联通块,\(rmax\)表示次大的联通块,\(mins\)表示最小的联通块,那么答案一定在\([rmax,maxs]\)之间,而且最小化最大值我们可以考虑二分

    然后要分成两种情况
    若最大联通块是某一个儿子的子树,这种情况很好处理,我们用线段树合并计算出每个子树可以取的子树大小(不包括它本身),然后判断一下是否有大小在\([maxs-mid,mid-mins]\)中的子树就好了。

    若最大联通块是父节点所在联通块的子树,这种情况比较麻烦,我们需要把点分成两种,一种是在\(x\)到根节点路径上的,一种是不在那个上面的。
    用树状数组记录一下在\(x\)到根节点路径上的子树大小,然后用总共的减去树状数组的和之前线段树那个在\(x\)子树内的就是不在到根节点路径上的,这些和之前那样查询就好了。
    剩下在到根路径上的节点的子树大小都减少了\(siz_x\),我们将查询的区间右移\(siz_x\)位就好了,用刚刚那个树状数组就好了

    时间复杂度\(O(n\log^2 n)\)


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define lowbit(x) (x&-x)
    using namespace std;
    const int N=1e5+10;
    struct node{
    	int to,next;
    }a[N];
    int n,tot,fa[N],deg[N],ls[N],rt[N],siz[N],ans[N];
    struct SegTree{
    	int w[N<<5],ls[N<<5],rs[N<<5],cnt;
    	int Change(int x,int L,int R,int pos){
    		int p=++cnt;w[p]=w[x]+1;
    		if(L==R)return p;int mid=(L+R)>>1;
    		if(pos<=mid)ls[p]=Change(ls[x],L,mid,pos),rs[p]=rs[x];
    		else rs[p]=Change(rs[x],mid+1,R,pos),ls[p]=ls[x];
    		return p;
    	}
    	int Ask(int x,int L,int R,int l,int r){
    		if(!x)return 0;
    		if(L==l&&R==r)return w[x];int mid=(L+R)>>1;
    		if(r<=mid)return Ask(ls[x],L,mid,l,r);
    		if(l>mid)return Ask(rs[x],mid+1,R,l,r);
    		return Ask(ls[x],L,mid,l,mid)+Ask(rs[x],mid+1,R,mid+1,r);
    	}
    	int Merge(int x,int y){
    		if(!x||!y)return x+y;
    		int p=++cnt;w[p]=w[x]+w[y];
    		ls[p]=Merge(ls[x],ls[y]);
    		rs[p]=Merge(rs[x],rs[y]);
    		return p;
    	}
    }T;
    struct TreeBinary{
    	int t[N];
    	void Change(int x,int val){
    		while(x<=n){
    			t[x]+=val;
    			x+=lowbit(x);
    		}
    		return;
    	}
    	int Ask(int x){
    		int ans=0;
    		while(x){
    			ans+=t[x];
    			x-=lowbit(x);
    		}
    		return ans;
    	}
    }B,D;
    void addl(int x,int y){
    	a[++tot].to=y;
    	a[tot].next=ls[x];
    	ls[x]=tot;return;
    }
    void dfs(int x){
    	siz[x]=1;
    	for(int i=ls[x];i;i=a[i].next){
    		int y=a[i].to;dfs(y);siz[x]+=siz[y];
    		rt[x]=T.Change(rt[x],1,n,siz[y]);
    		rt[x]=T.Merge(rt[x],rt[y]);
    	}
    	D.Change(siz[x],1);
    	return;
    }
    int epe(int L,int R,int x){
    	if(L>R)return 0;
    	return D.Ask(R)-D.Ask(L-1)+B.Ask(R+siz[x])-B.Ask(L+siz[x]-1)-T.Ask(rt[x],1,n,L,R);
    }
    void work(int x){
    	if(x==36449)
    		x++,x--;
    	if(deg[x]<2){ans[x]=max(siz[1]-siz[x],siz[a[ls[x]].to]);return;}
    	int p=0,mins=n,maxs=0,rmax=0;
    	for(int i=ls[x];i;i=a[i].next){
    		int y=a[i].to;
    		if(siz[y]>maxs)rmax=maxs,maxs=siz[y],p=y;
    		else if(siz[y]>rmax)rmax=siz[y];
    		mins=min(mins,siz[y]);
    	}
    	if(siz[1]-siz[x]>maxs){
    		rmax=maxs;maxs=siz[1]-siz[x];
    		mins=min(mins,siz[1]-siz[x]);
    		int L=rmax,R=maxs-1;
    		while(L<=R){
    			int mid=(L+R)>>1;
    			int l=maxs-mid,r=mid-mins;
    			if(epe(l,r,x))R=mid-1;
    			else L=mid+1;
    		}
    		ans[x]=L;return;
    	}
    	else if(fa[x]){
    		if(siz[1]-siz[x]>rmax)rmax=siz[1]-siz[x];
    		mins=min(mins,siz[1]-siz[x]);
    	}
    	int L=rmax,R=maxs-1;
    	while(L<=R){
    		int mid=(L+R)>>1;
    		int l=maxs-mid,r=mid-mins;
    		if(T.Ask(rt[p],1,n,l,r))R=mid-1;
    		else L=mid+1;
    	}
    	ans[x]=L;
    	return;
    }
    void calc(int x){
    	D.Change(siz[x],-1);
    	work(x);
    	B.Change(siz[x],1);
    	for(int i=ls[x];i;i=a[i].next)
    		calc(a[i].to);
    	B.Change(siz[x],-1);
    	D.Change(siz[x],1);
    }
    int main()
    {
    	freopen("traffic.in","r",stdin);
    	freopen("traffic.out","w",stdout);
    	scanf("%d",&n);
    	for(int i=2;i<=n;i++){
    		scanf("%d",&fa[i]);
    		deg[fa[i]]++;deg[i]++;
    		addl(fa[i],i);
    	}
    	dfs(1);D.Change(siz[1],-1);
    	work(1);B.Change(siz[1],1);
    	for(int i=ls[1];i;i=a[i].next)
    		calc(a[i].to);
    	for(int i=1;i<=n;i++)
    		printf("%d\n",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    vnc mirror driver cannot be installed rdp connection解决方法
    安装.Net Framework 4.6.2时出现“无法建立到信任根颁发机构的证书链”解决方法 一、错误
    MCP2515 CAN总线模块介绍
    HarmonyOS HiSpark Wi-Fi IoT套件】使用HiBurn烧录鸿蒙.bin文件到Hi3861芯片
    鸿蒙开发板hi3861 VScode DevEco无法使用 compilerPath“riscv32-unknown-elf-gcc
    c# http协议 web api发送,获取方法-获取网页数据
    JS图片按比例加载
    哪些法宝值得接
    法宝合成时的五行位置分配是什么
    跨数据库导数据,可自选行内容
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14437174.html
Copyright © 2020-2023  润新知