zoukankan      html  css  js  c++  java
  • [BZOJ 1095][ZJOI2007]Hide 捉迷藏

    [BZOJ 1095][ZJOI2007]Hide 捉迷藏

    题意

    给定一棵 (n) 个点的树以及 (q) 次操作. 操作有两种, 一种是求有效点之间的最大距离, 另一种是将一个点的有效状态反转.

    (nle 1 imes 10^5,qle 5 imes 10^5).

    题解

    好像老老实实写动态点分的在榜上都垫底了qaq

    我们可以发现这个求两点之间最大距离非常的点分治, 为了处理修改有效点的问题, 我们需要动态点分治.

    首先我们把点分树建出来, 接下来的操作对点分树进行(距离按原树算).

    然后对于每个点, 我们记录两个平衡树/堆, 一个 (len) 表示这个子树中的所有点到根的父亲的距离, 一个 (maxd) 表示各个子结点的 (len) 中的最大值. 全局再维护一个 (all) 存储每个点的 (maxd) 中的最大值与次大值之和.

    不难发现每次查询的时候取 (all) 中的最大值即是答案.

    修改的时候距离用LCA计算, 每次先把当前点可能产生的贡献删除, 修改后再插回去.

    初始化的时候有个技巧, DFS当前分治子树的时候 (dis[root]) 保存的是父分治子树的根到当前点的距离. 发现这刚好就是我们要算的东西, 直接insert进set就好了.

    复杂度 (O((n+q)log^2 n)).

    参考代码

    #include <bits/stdc++.h>
    
    const int MAXV=1e5+10;
    const int MAXE=2e5+10;
    typedef std::multiset<int,std::greater<int>> multiset;
    
    struct Edge{
    	int from;
    	int to;
    	Edge* next;
    };
    Edge E[MAXE];
    Edge* head[MAXV];
    Edge* topE=E;
    
    int n;
    int q;
    int root;
    int cursize;
    int prt[MAXV];
    int dis[MAXV];
    int top[MAXV];
    int son[MAXV];
    int size[MAXV];
    int pprt[MAXV];
    int deep[MAXV];
    bool off[MAXV];
    bool vis[MAXV];
    int msize[MAXV];
    
    multiset all;
    multiset len[MAXV];
    multiset maxd[MAXV];
    
    char GetCmd();
    int ReadInt();
    void Solve(int);
    int Dis(int,int);
    int LCA(int,int);
    void DFS(int,int);
    void Insert(int,int);
    void Modify(int,bool);
    void DFS(int,int,int);
    void GetRoot(int,int);
    int Export(const multiset&);
    
    int main(){
    	n=ReadInt();
    	for(int i=1;i<n;i++){
    		int a=ReadInt(),b=ReadInt();
    		Insert(a,b);
    		Insert(b,a);
    	}
    	DFS(1,0,0);
    	DFS(1,1);
    	cursize=n;
    	msize[0]=n;
    	GetRoot(1,0);
    	Solve(root);
    	q=ReadInt();
    	while(q--){
    		if(GetCmd()=='C'){
    			int x=ReadInt();
    			Modify(x,off[x]^=1);
    		}
    		else
    			printf("%d
    ",*all.begin());
    	}
    	return 0;
    }
    
    void Modify(int x,bool opt){
    	if(maxd[x].size()>1)
    		all.erase(all.find(Export(maxd[x])));
    	if(opt)
    		maxd[x].erase(maxd[x].find(0));
    	else
    		maxd[x].insert(0);
    	if(maxd[x].size()>1)
    		all.insert(Export(maxd[x]));
    	for(int p=x;prt[p]!=0;p=prt[p]){
    		if(maxd[prt[p]].size()>1)
    			all.erase(all.find(Export(maxd[prt[p]])));
    		if(!len[p].empty())
    			maxd[prt[p]].erase(maxd[prt[p]].find(*len[p].begin()));
    		if(opt)
    			len[p].erase(len[p].find(Dis(prt[p],x)));
    		else
    			len[p].insert(Dis(prt[p],x));
    		if(!len[p].empty())
    			maxd[prt[p]].insert(*len[p].begin());
    		if(maxd[prt[p]].size()>1)
    			all.insert(Export(maxd[prt[p]]));
    	}
    }
    
    void DFS(int root,int prt,multiset& len){
    	if(dis[root]!=0)
    		len.insert(dis[root]);
    	dis[root]=dis[prt]+1;
    	for(Edge* i=head[root];i!=NULL;i=i->next)
    		if(i->to!=prt&&!vis[i->to])
    			DFS(i->to,root,len);
    }
    
    void Solve(int root){
    	vis[root]=true;
    	if(dis[root]!=0)
    		len[root].insert(dis[root]);
    	dis[root]=0;
    	for(Edge* i=head[root];i!=NULL;i=i->next){
    		if(!vis[i->to])
    			DFS(i->to,root,len[root]);
    	}
    	maxd[root].insert(0);
    	for(Edge* i=head[root];i!=NULL;i=i->next){
    		if(!vis[i->to]){
    			::root=0;
    			cursize=size[i->to];
    			GetRoot(i->to,root);
    			int son=::root;
    			prt[son]=root;
    			Solve(son);
    			if(!len[son].empty())
    				maxd[root].insert(*len[son].begin());
    		}
    	}
    	if(maxd[root].size()>1)
    		all.insert(Export(maxd[root]));
    }
    
    void GetRoot(int root,int prt){
    	size[root]=1;
    	msize[root]=0;
    	for(Edge* i=head[root];i!=NULL;i=i->next){
    		if(!vis[i->to]&&i->to!=prt){
    			GetRoot(i->to,root);
    			size[root]+=size[i->to];
    			msize[root]=std::max(msize[root],size[i->to]);
    		}
    	}
    	msize[root]=std::max(msize[root],cursize-size[root]);
    	if(msize[root]<msize[::root])
    		::root=root;
    }
    
    inline void Insert(int from,int to){
    	topE->from=from;
    	topE->to=to;
    	topE->next=head[from];
    	head[from]=topE++;
    }
    
    void DFS(int root,int prt,int deep){
    	size[root]=1;
    	pprt[root]=prt;
    	::deep[root]=deep;
    	for(Edge* i=head[root];i!=NULL;i=i->next){
    		if(i->to!=prt){
    			DFS(i->to,root,deep+1);
    			size[root]+=size[i->to];
    			if(size[i->to]>size[son[root]])
    				son[root]=i->to;
    		}
    	}
    }
    
    void DFS(int root,int top){
    	::top[root]=top;
    	if(son[root])
    		DFS(son[root],top);
    	for(Edge* i=head[root];i!=NULL;i=i->next)
    		if(i->to!=pprt[root]&&i->to!=son[root])
    			DFS(i->to,i->to);
    }
    
    inline int Dis(int x,int y){
    	return deep[x]+deep[y]-2*(deep[LCA(x,y)]);
    }
    
    inline int LCA(int x,int y){
    	while(top[x]!=top[y]){
    		if(deep[top[x]]<deep[top[y]])
    			std::swap(x,y);
    		x=pprt[top[x]];
    	}
    	if(deep[x]>deep[y])
    		std::swap(x,y);
    	return x;
    }
    
    inline int ReadInt(){
    	int x=0;
    	register char ch=getchar();
    	while(!isdigit(ch))
    		ch=getchar();
    	while(isdigit(ch)){
    		x=x*10+ch-'0';
    		ch=getchar();
    	}
    	return x;
    }
    
    inline char GetCmd(){
    	register char ch=getchar();
    	while(ch!='C'&&ch!='G')
    		ch=getchar();
    	return ch;
    }
    
    inline int Export(const multiset& s){
    	auto it=s.begin();
    	++it;
    	return *s.begin()+*it;
    }
    
    

  • 相关阅读:
    一 : Nacos简介
    性能指标:性能监控指标有哪些?
    性能测试的分类
    VLP16线用户手册.md
    LibLas学习笔记
    从深度图中提取物体边界
    从点云数据生成深度图像
    微创社2期:从0到1,技术图书创作3步走(张慧敏、高飞、张杰、王凤辉)
    中国.NET:各地微软技术俱乐部汇总(更新中...)
    编译lua-5.3.5时出错解决方法
  • 原文地址:https://www.cnblogs.com/rvalue/p/10507425.html
Copyright © 2011-2022 走看看