• 线段树分治


    DAY2模拟被完爆了w

    来学一波线段树分治 原来一直拿它口胡其实没写过。。

    然鹅这个东西和线段树的关系 就像点分治和点分树一样
    并不用建出来 但遍历顺序是一致的
    从上到下 从左儿子到右儿子 访问“线段树”的所有节点
    每个节点表示一个区间 当然维护的也是区间里的值
    这就要求我们维护的东西满足区间加法
    比如并查集啦线性基啦什么的

    先来一道例题
    bzoj4025二分图

    当然先考虑边的出现没有时间限制的话我们怎么做
    对于一张无向图随便给它一个根 那么如果从这个根暴力染色的话
    就是一黑一白一黑一白。。。显然所有的环都要满足长度为偶数

    如果一个连通分量满足自己是一个二分图
    现在用一条边把它和另一个连通分量连起来
    那么它们还是一个二分图(如果被连接的两点是一个颜色,把其中一个图的所有点颜色反过来就好了)
    而且如果用两个联通分量中各自的任意一个点来负责连接,显然也是成立的,证明和上面一样
    所以连接那两个根就好啦

    所以不合法的情况出现 仅当两点u, v已经联通,这时又来的一条边,让他们变成了一个奇环
    而我们给了这个连通分量一个根rt
    如果u, v到根的路径不重叠
    那么这两点到根rt的距离dis[u] + dis[v]显然是一个偶数(因为加上新增的一条边就是奇数了嘛
    如果重叠呢?
    发现重叠部分的贡献2dis[lca(u, v)]也是一个偶数 不对结果造成影响

    所以我们维护并查集就好啦

    首先把边们按照出现时间排序
    每次取一个Mid, 像线段树分区间一样把边的时间区间分下去
    如果到了某个节点发现此时有奇环 那么这段时间的图都不满足二分图性质
    如果到了叶子节点还没凉 那么在这个时刻图一定是二分图

    #include <cmath>
    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <complex>
    #include <ctime>
    #include <vector>
    #define mp(x, y) make_pair(x, y)
    using namespace std;
    typedef pair<int, int> PII;
    const int N = 4e5 + 5;
    int n, m, T; 
    struct Line{int u, v, s, t;};
    vector<Line> vec[N << 2];
    struct UFS{
    	int uu[N], vv[N], rec[N], fa[N], dis[N], dep[N], top; //这个dep其实是size... 
    	void init(){for(int i = 1; i <= n; ++i) fa[i] = i;}
    	int find_f(int x){return fa[x] == x ? x : find_f(fa[x]);}
    	int find_w(int x){return fa[x] == x ? dis[x] : find_w(fa[x]) ^ dis[x];}
    	int merge(int x, int y, int w){
    		if(dep[x] < dep[y]){//把x合并到y里 
    			fa[x] = y, dep[y] += dep[x], dis[x] = w;
    			uu[++top] = x, vv[top] = y;
    		}
    		else {
    		    fa[y] = x, dep[x] += dep[y], dis[y] = w;
    			uu[++top] = y, vv[top] = x;	
    		}
    	}
    	void undo(int x){
    		while(top && top > x){
    			fa[uu[top]] = uu[top], dep[vv[top]] -= dep[uu[top]], dis[uu[top]] = 0, --top; //dis!
    		}
    	}
    }ufs;
    
    void SegDiv(int L, int R, int rt){
    	int Mid = L + ((R - L) >> 1), beg = ufs.top, ls = (rt << 1), rs = ((rt << 1) | 1);
    	for(int i = vec[rt].size() - 1; i >= 0; --i){
    		Line e = vec[rt][i];
    		if(e.s <= L && e.t >= R){
    			int x = ufs.find_f(e.u), y = ufs.find_f(e.v);
    		    int wu = ufs.find_w(e.u), wv = ufs.find_w(e.v);
    		    if(x != y){ufs.merge(x, y, wu ^ wv ^ 1); continue;}
    		    if(!(wu ^ wv)){
    		    	for(int i = L; i <= R; ++i) printf("No
    "); 
    		    	ufs.undo(beg); return ;
    		    }
    		}
    		else if(e.t <= Mid) vec[ls].push_back(e);
    		else if(e.s > Mid) vec[rs].push_back(e);
    		else vec[ls].push_back(e), vec[rs].push_back(e);
    	}
    	if(L == R) printf("Yes
    ");
    	else SegDiv(L, Mid, ls), SegDiv(Mid + 1, R, rs);
        ufs.undo(beg);
    }
    
    int main(){
    	scanf("%d%d%d", &n, &m, &T);
    	for(int i = 1, uu, vv, ss, tt; i <= m; ++i){
    		scanf("%d%d%d%d", &uu, &vv, &ss, &tt);
    		vec[1].push_back((Line){uu, vv, ss + 1, tt});
    	}
    	ufs.init();
    	SegDiv(1, T, 1);
    	/*
    	输入
    	每个边插入
    	线段树分治
    	    考虑当前区间已经被覆盖的
    		false NO 
    		true判断叶子返回 /下放 
    		redo 
    	*/
        return 0;	
    }
    
    
  • 相关阅读:
    清除大文本中的html标签
    页面中富文本的使用
    artDialog的几种基本使用
    SQL基础-->层次化查询(START BY ... CONNECT BY PRIOR)[转]
    Struts2
    js中window.location的用法
    keycode键盘 按键
    jQuery升级踩坑之路
    生成唯一随机码的方法及优缺点分析
    百度API的经历,怎样为多个点添加带检索功能的信息窗口
  • 原文地址:https://www.cnblogs.com/hjmmm/p/10669888.html
Copyright © 2020-2023  润新知