zoukankan      html  css  js  c++  java
  • 虚树

    有时,我们只需要知道树上一些关键点组合而成的信息,就可以知道答案。
    可以建出这些点的虚树。
    虚树有静态和动态两种。
    静态虚树就是网上讲的普通虚树。
    按照dfs序从小到大添加节点,每次更新虚树。
    维护一个栈,表示最右链。
    根据lca分类讨论。
    实际上这就是模拟dfs的过程。
    所以如果要树dp,在建虚树的过程中可以顺便完成,减少代码量。
    建立静态虚树的代码如下:

    void ins(int x){
    	if(!tp){
    		st[++tp]=x;
    		return;
    	}
    	int lc=lca(st[tp],x);
    	if(lc==st[tp])st[++tp]=x;
    	else{
    		while(tp>1&&id[st[tp-1]]>=id[lc]){
    			g[st[tp-1]].push_back(st[tp]);
    			tp--;
    		}
    		if(lc!=st[tp]){
    			g[lc].push_back(st[tp]);
    			st[tp]=lc;
    		}
    		st[++tp]=x;
    	}
    }
    void bd(vector<int>va){
    	tp=0;
    	sort(va.begin(),va.end(),cp);
    	auto it=unique(va.begin(),va.end());
    	va.erase(it,va.end());
    	for(int i=0;i<va.size();i++)
    		ins(va[i]);
    	for(int i=2;i<=tp;i++)
    		g[st[i-1]].push_back(st[i]);
    }
    

    实际上,如果询问数较少,可以直接按照定义建出虚树。时间复杂度(O(n))(n)为点数。
    动态虚树基于如下结论:
    如果把所有点排序,排序后数组设为a。
    把dis[lca(a[i],a[i+1])]和dis[lca(a[n],a[1])]加起来,得到了链并(虚树大小)的两倍。
    注意链并是边权。
    ([SDOI2015]寻宝游戏)
    实际上求链并还可以永久标记线段树+轻重链剖分。但是和正解没有什么关系。
    两种虚树分别有擅长/不擅长的领域。
    动态虚树基于一个公式,在一些题目中这个公式可以方便维护。
    而且有动态加点只能动态虚树。
    但是如果要知道虚树的形态,只能用静态虚树。
    虚树还有一个离线排序的技巧。
    每次建虚树要排序,这样子时间复杂度是nlogn的。
    但是如果没有强制在线,可以使用n个链表b,b[i]存储dfs序为i的节点。
    离线后从小到大遍历b,把b的元素插回去即可。
    静态虚树例题:
    [SDOI2018]战略游戏
    [SDOI2011]消耗战
    mx的仙人掌(没做)
    xr2 永恒
    WC2018 通道
    暴力写挂(没用虚树做)
    ccADJLEAF2(想出来了,没做)
    NOI2018 情报中心
    CF1336F(和情报中心差不多,没做)
    [GDOI2019]颜色(想出来了,没做)
    [HNOI2014]世界树
    [SDOI2019]世界地图(未完全理解)
    jzoj5058/洛谷 树上游戏
    [HNOI2018]毒瘤
    [SDOI2017]天才黑客
    河童重工(没做)
    动态虚树例题:
    [SDOI2015]寻宝游戏
    [ZJOI2019]语言
    bzoj七彩树(看懂了题解,没做)
    动态半平面交(七彩树强化版)

  • 相关阅读:
    查看tls指纹
    并行流
    方法引入2
    方法引入
    Optional.ofNullable
    stream.filter
    stream.skip limit
    反射
    Optional orElseGet
    nginx 预压缩(gzip)
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/13647014.html
Copyright © 2011-2022 走看看