zoukankan      html  css  js  c++  java
  • 线段树分治

    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;	
    }
    
    
  • 相关阅读:
    django中的FBV和CBV
    RESTful
    REST
    18.前端路由router-08权限控制
    17.前端路由router-07keep-alive
    16.前端路由router-06动态路由
    15.前端路由router-05嵌套路由
    14.前端路由router-04编程式导航
    13.前端路由router-03路由参数
    java基础总结
  • 原文地址:https://www.cnblogs.com/hjmmm/p/10669888.html
Copyright © 2011-2022 走看看