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;
    }
    
    
  • 相关阅读:
    封装成帧、帧定界、帧同步、透明传输(字符计数法、字符串的首尾填充法、零比特填充的首尾标志法、违规编码法)
    计算机网络之数据链路层的基本概念和功能概述
    物理层设备(中继器、集线器)
    计算机网络之传输介质(双绞线、同轴电缆、光纤、无线电缆、微波、激光、红外线)
    计算机网络之编码与调制
    0953. Verifying an Alien Dictionary (E)
    1704. Determine if String Halves Are Alike (E)
    1551. Minimum Operations to Make Array Equal (M)
    0775. Global and Local Inversions (M)
    0622. Design Circular Queue (M)
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8276862.html
Copyright © 2011-2022 走看看