zoukankan      html  css  js  c++  java
  • 动态点分治:Bzoj1095: [ZJOI2007]Hide 捉迷藏

    简介

    这是我自己的一点理解,可能写的不好
    点分治都学过吧。。
    点分治每次找重心把树重新按重心的深度重建成了一棵新的树,称为分治树
    这个树最多有log层。。。
    动态点分治:记录下每个重心的上一层重心,这棵分治树就确定了
    修改就暴力在分治树中向上改,反正是log的
    至于为什么叫动态点分治我不知道。。。我觉得就是点分治
    做题时最主要的难点不在点分治,在于维护什么和怎样维护

    例题

    Bzoj1095: [ZJOI2007]Hide 捉迷藏

    先搞出这个分治树,然后基本和点分治无关了

    以下基于分治树
    每个重心开两个堆
    第一个堆记录子树中所有节点到重心的距离
    第二个堆记录所有子节点的第一个堆的堆顶
    那么一个节点的第二个堆堆中的最大值和次大值加起来就是子树中经过这个节点的最长链
    然后开一个全局的堆,记录所有第二个堆中最大值和次大值之和
    堆顶就是答案

    修改就分治树中暴跳重心,大力讨论一番
    代码和思路来自hzwer

    # include <bits/stdc++.h>
    # define RG register
    # define IL inline
    # define Fill(a, b) memset(a, b, sizeof(a))
    using namespace std;
    typedef long long ll;
    const int _(2e5 + 10);
    
    IL ll Read(){
    	RG ll x = 0, z = 1; RG char c = getchar();
    	for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    	for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    	return x * z;
    }
    
    int n, nxt[_], to[_], fst[_], cnt, deep[_], size[_], frt[_], rt, mx[_], sz;
    int eul[20][_], pw[20] = {1}, lg[_], id[_], tot;
    bool cls[_], vis[_];
    struct Heap{
    	priority_queue <int> A, B;
    	IL void Push(RG int x){  A.push(x);  }
    
    	IL void Del(RG int x){  B.push(x);  }
    
    	IL void Pop(){  while(!B.empty() && A.top() == B.top()) A.pop(), B.pop(); A.pop();   }
    
    	IL int Top(){  while(!B.empty() && A.top() == B.top()) A.pop(), B.pop(); return !A.empty() ? A.top() : 0;  }
    
    	IL int Size(){  return A.size() - B.size();  }
    
    	IL int _Top(){  if(Size() < 2) return 0; RG int x = Top(); Pop(); RG int y = Top(); Push(x); return y;  }
    } A, B[_], C[_];
    
    IL void Add(RG int u, RG int v){  to[cnt] = v; nxt[cnt] = fst[u]; fst[u] = cnt++;  }
    /***********************************建立分治树***************************************/
    IL void Getroot(RG int u, RG int ff){
    	size[u] = 1; mx[u] = 0;
    	for(RG int e = fst[u]; e != -1; e = nxt[e]){
    		if(to[e] == ff || vis[to[e]]) continue;
    		Getroot(to[e], u);
    		size[u] += size[to[e]];
    		mx[u] = max(mx[u], size[to[e]]);
    	}
    	mx[u] = max(mx[u], sz - size[u]);
    	if(mx[u] < mx[rt]) rt = u;
    }
    
    IL void Create(RG int u, RG int ff){
    	frt[u] = ff; /*记录上层重心*/ vis[u] = 1;
    	for(RG int e = fst[u]; e != -1; e = nxt[e]){
    		if(vis[to[e]]) continue;
    		rt = 0; sz = size[to[e]];
    		Getroot(to[e], 0);
    		Create(rt, u);
    	}
    }
    /***********************************************************************************/
    IL void Dfs(RG int u, RG int ff){
    	eul[0][++cnt] = deep[u]; id[u] = cnt;
    	for(RG int e = fst[u]; e != -1; e = nxt[e]){
    		if(to[e] == ff) continue;
    		deep[to[e]] = deep[u] + 1;
    		Dfs(to[e], u);
    		eul[0][++cnt] = deep[u];
    	}
    }
    
    IL int Query(RG int x, RG int y){
    	x = id[x]; y = id[y]; if(x > y) swap(x, y); RG int len = y - x + 1;
    	return min(eul[lg[len]][x], eul[lg[len]][y - pw[lg[len]] + 1]);
    }
    
    IL int MaxDis(RG int x, RG int y){  return deep[x] + deep[y] - 2 * Query(x, y);  }
    
    IL void Close(RG int x, RG int y){
    	if(x == y){
    		B[x].Push(0);
    		if(B[x].Size() == 2) A.Push(B[x].Top());
    	}
    	if(!frt[x]) return;
    	RG int ff = frt[x], dis = MaxDis(ff, y), tmp = C[x].Top(); C[x].Push(dis);
    	if(dis > tmp){
    		RG int mmx = B[ff].Top() + B[ff]._Top(), sszz = B[ff].Size();
    		if(tmp) B[ff].Del(tmp); B[ff].Push(dis);
    		RG int _mmx = B[ff].Top() + B[ff]._Top();
    		if(_mmx > mmx){
    			if(sszz >= 2) A.Del(mmx);
    			if(B[ff].Size() >= 2) A.Push(_mmx);
    		}
    	}
    	Close(ff, y);
    }
    
    IL void Open(RG int x, RG int y){
    	if(x == y){
    		if(B[x].Size() == 2) A.Del(B[x].Top());
    		B[x].Del(0);
    	}
    	if(!frt[x]) return;
    	RG int ff = frt[x], dis = MaxDis(ff, y), tmp = C[x].Top(); C[x].Del(dis);
    	if(dis == tmp){
    		RG int mmx = B[ff].Top() + B[ff]._Top(), sszz = B[ff].Size();
    		B[ff].Del(dis); if(C[x].Top()) B[ff].Push(C[x].Top());
    		RG int _mmx = B[ff].Top() + B[ff]._Top();
    		if(_mmx < mmx){
    			if(sszz >= 2) A.Del(mmx);
    			if(B[ff].Size() >= 2) A.Push(_mmx);
    		}
    	}
    	Open(ff, y);
    }
    
    int main(RG int argc, RG char* argv[]){
        Fill(fst, -1); tot = sz = n = Read(); mx[0] = 2e9;
    	for(RG int i = 2; i < _; ++i) lg[i] = lg[i >> 1] + 1;
    	for(RG int i = 1; i < 20; ++i) pw[i] = pw[i - 1] << 1;
        for(RG int i = 1, u, v; i < n; i++) u = Read(), v = Read(), Add(u, v), Add(v, u);
    	cnt = 0; Dfs(1, 0);
    	for(RG int i = 1; i <= lg[cnt]; ++i)
    		for(RG int j = 1; j + pw[i] - 1 <= cnt; ++j)
    			eul[i][j] = min(eul[i - 1][j], eul[i - 1][j + pw[i - 1]]);
    	Getroot(1, 0); Create(rt, 0);
    	for(RG int i = 1; i <= n; ++i) C[i].Push(0), cls[i] = 1, Close(i, i);
    	for(RG int Q = Read(); Q; --Q){
    		RG char op; RG int x; scanf(" %c", &op);
    		if(op == 'G'){
    			if(tot <= 1) printf("%d
    ", tot - 1);
    			else printf("%d
    ", A.Top());
    		}
    		else{
    			x = Read();
    			if(cls[x]) Open(x, x), --tot, cls[x] = 0;
    			else Close(x, x), ++tot, cls[x] = 1;
    		}
    	}
        return 0;
    }
    
    
  • 相关阅读:
    SEO(Business)
    C#数组去掉重复的元素
    文件创建与文件格式的修改
    Filter(20160815)
    OmniGraffle导入stencils的两个方法以及优质的stencils下载网站推荐
    在Axure RP 8.0 中使用 Font Awesome 图标库完成设计并能在其他未安装该字体的电脑离线预览的方法
    社会性动物(艾略特•阿伦森)
    MacTex 在XeLaTex编译状态下插入的pdf格式图片无法显示问题的解决方案
    Markdown,别来无恙!
    男人来自火星 女人来自金星(约翰·格雷)
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8276862.html
Copyright © 2011-2022 走看看