zoukankan      html  css  js  c++  java
  • 【BZOJ1095】捉迷藏(动态点分治)

    【BZOJ1095】捉迷藏(动态点分治)

    题面

    BZOJ

    题解

    动态点分治板子题

    假设,不考虑动态点分治
    我们来想怎么打暴力:
    (O(n)DP)求树的最长链
    一定都会。不想解释了

    所以,利用上面的思想
    对于每个点,维护子树到他的最长链
    以及子树到他的次长链
    把这两个玩意拼起来就可能是答案啦

    所以,每个点维护两个堆
    一个维护子树上的点到他的距离
    一个维护所有子树的前面那个堆的最大值
    也就是所以子树中,到达当前点的最长链

    再在全局维护一个堆
    记录每个点最长链和次长链的和

    这样子就可以动态的维护了
    但是,因为细节很多
    一定要讨论详细

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define MAX 120000
    inline int read()
    {
    	int x=0,t=1;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=-1,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return x*t;
    }
    int n;
    struct Priority_queue
    {
    	priority_queue<int> q,d;
    	void push(int x){q.push(x);}
    	void del(int x){d.push(x);}
    	void pop()
    		{
    			while(!d.empty()&&q.top()==d.top())q.pop(),d.pop();
    			q.pop();
    		}
    	int top()
    		{
    			while(!d.empty()&&q.top()==d.top())q.pop(),d.pop();
    			if(q.empty())return 0;
    			return q.top();
    		}
    	int size(){return q.size()-d.size();}
    	int s_top()
    		{
    			if(size()<2)return 0;
    			int t=top();pop();
    			int ret=top();push(t);
    			return ret;
    		}
    }A,B[MAX],C[MAX];
    struct Line{int v,next;}e[MAX<<1];
    int h[MAX],cnt=1;
    inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
    /************************************************************************/
    int dfn[MAX],top[MAX],dep[MAX],ssize[MAX],hson[MAX],fa[MAX];
    void dfs1(int u,int ff)
    {
    	fa[u]=ff;ssize[u]=1;dep[u]=dep[ff]+1;
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(v==ff)continue;
    		dfs1(v,u);
    		ssize[u]+=ssize[v];
    		if(ssize[hson[u]]<ssize[v])hson[u]=v;
    	}
    }
    void dfs2(int u,int tp)
    {
    	top[u]=tp;
    	if(hson[u])dfs2(hson[u],tp);
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(v==fa[u]||v==hson[u])continue;
    		dfs2(v,v);
    	}
    }
    int LCA(int u,int v)
    {
    	while(top[u]!=top[v])
    	{
    		if(dep[top[u]]<dep[top[v]])swap(u,v);
    		u=fa[top[u]];
    	}
    	return dep[u]<dep[v]?u:v;
    }
    int Dis(int u,int v)
    {
    	return dep[u]+dep[v]-dep[LCA(u,v)]*2;
    }
    /************************************************************************/
    int size[MAX],Fa[MAX];
    int cl[MAX],tot,Size,minr;
    int root;
    bool vis[MAX];
    void Getroot(int u,int ff)
    {
    	size[u]=1;
    	int ret=0;
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(v==ff||vis[v])continue;
    		Getroot(v,u);
    		size[u]+=size[v];
    		ret=max(ret,size[v]);
    	}
    	ret=max(ret,Size-size[u]);
    	if(ret<minr)minr=ret,root=u;
    }
    void Div(int u,int ff)//把树给割开
    {
    	vis[u]=true;Fa[u]=ff;
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(v==ff||vis[v])continue;
    		minr=n;Size=size[v];
    		Getroot(v,u);
    		Div(root,u);
    	}
    }
    //A:全局用来维护最大距离,存每个B的最大值和次大值之和(也就是拼出的链)
    //B:维护所有子树到当前点的最长距离,也就是所有子节点C的top
    //C:维护所有子树到当前点的距离
    void Turn_Off(int u,int v)//关掉v的灯
    {
    	if(u==v)//如果就是自己这里
    	{
    		B[u].push(0);//插一个0进来,自己到自己有长度为0的链
    		if(B[u].size()==2)A.push(B[u].top()); 
            //如果size超过2,意味着有超过两条链,就可能拼出一个答案
    		//如果size等于2,有一条链和一条长度为0的链
    	}
    	if(!Fa[u])return;//到了顶上了
    	int ff=Fa[u],D=Dis(ff,v),tmp=C[u].top();
    	C[u].push(D);//对上一层的贡献
    	if(D>tmp)//比当前层给的贡献要大一些
    	{
    		int mx=B[ff].top()+B[ff].s_top(),sz=B[ff].size();
    		//mx是去两条链拼出一个可能的答案
    		if(tmp)B[ff].del(tmp);//上一层的值要被替换掉
    		B[ff].push(D);//换成一个更大的值
    		int now=B[ff].top()+B[ff].s_top();//当前的两条最长链
    		if(now>mx)//比原来的那条链要大一些
    		{
    			if(sz>=2)A.del(mx);//如果超过两条链就把原来的答案给删掉
    			if(B[ff].size()>=2)A.push(now);//换上一个新的答案
    		}
    	}
    	Turn_Off(ff,v);//往上递归
    }
    void Turn_On(int u,int v)//打开v的灯
    {
    	if(u==v)//如果就是自己这里
    	{
    		if(B[u].size()==2)A.del(B[u].top()); 
    		B[u].del(0);
    	}
    	if(!Fa[u])return;//到了顶上了
    	int ff=Fa[u],D=Dis(ff,v),tmp=C[u].top();
    	C[u].del(D);
    	if(D==tmp)
    	{
    		int mx=B[ff].top()+B[ff].s_top(),sz=B[ff].size();
    		B[ff].del(D);
    		if(C[u].top())B[ff].push(C[u].top());
    		int now=B[ff].top()+B[ff].s_top();
    		if(now<mx)
    		{
    			if(sz>=2)A.del(mx);
    			if(B[ff].size()>=2)A.push(now);
    		}
    	}
    	Turn_On(ff,v);//往上递归
    }
    /************************************************************************/
    int main()
    {
    	n=read();
    	for(int i=1,a,b;i<n;++i)a=read(),b=read(),Add(a,b),Add(b,a);
    	dfs1(1,0);dfs2(1,1);
    	root=0;minr=Size=n;Getroot(1,0);
    	Div(root,0);
    	for(int i=1;i<=n;++i)C[i].push(0);
    	for(int i=1;i<=n;++i)cl[i]=1;//默认关上
    	for(int i=1;i<=n;++i)Turn_Off(i,i),++tot;
    	char ch[3];
    	int Q=read();
    	while(Q--)
    	{
    		scanf("%s",ch);
    		if(ch[0]=='G')
    		{
    			if(tot<=1)printf("%d
    ",tot-1);
    			else printf("%d
    ",A.top());
    		}
    		else
    		{
    			int x=read();
    			if(cl[x])Turn_On(x,x),tot--;
    			else Turn_Off(x,x),tot++;
    			cl[x]^=1;
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Roce ofed 环境搭建与测试
    Ubuntu 1804 搭建NFS服务器
    Redhat 8.0.0 安装与网络配置
    Centos 8.1 安装与网络配置
    SUSE 15.1 系统安装
    VSpare ESXi 7.0 基本使用(模板、iso、SRIOV)
    VSpare ESXi 7.0 服务器安装
    open SUSE leap 15.1 安装图解
    KVM虚拟机网卡连接网桥
    GitHub Action一键部署配置,值得拥有
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8278345.html
Copyright © 2011-2022 走看看