线段树分治学习笔记

名字高大上其实好学的一批…

多处理一类问题…类如"一条边会在 [L,R] 时刻出现"

线段树其实就是若干个区间 你可以用一种线段树分治 就是把线段树当做时间轴

因为一段区间在线段树上最多分成\(\log\)段?。所以线段树复杂度是 \(n \log n\)

void add(int a , int b , int l , int r , int rt , int id) {
	if(a <= l && r <= b) {
		vec[rt].push_back(id) ;
		return ;
	}
	int mid = l + r >> 1 ;
	if(a <= mid) add(a , b , l , mid , rt << 1 , id) ;
	if(b > mid) add(a , b , mid + 1 , r , rt << 1 | 1 , id) ;
}

每次分区间成 [L1,R1][L2=R1+1,R2][……]

\(L_1 = L R_n = R\) 这样就类似线段树了…

每次solve的时候是考虑下放标记一样的过程 最后再消除贡献罢了…

因为你每次是单点查询 \([L,R][L==R]\) 所以直接考虑做 [L,R] 的时候把 [L,R] 存的"标记"(标记指的是分成的log个操作)下放…然后再递归求解

递归完之后就消除当前贡献就可以了。。(用栈存一下当前位置 递归下去的位置 这样就可以回归原位了quq)

补个坑 = =
这玩意就是可回退栈 = =
随便写写就行了

板子

二分图的判定是不存在奇环…不能路径压缩的并查集…因为这样才能求dis…

#include <bits/stdc++.h>
#define rep(i , x , y) for(register int i = (x) , _## i = (y + 1) ; i < _## i ; i ++)
#define Rep(i , x , y) for(register int i = (x) , _## i = (y - 1) ; i > _## i ; i --)
using namespace std ;
#define int long long
using ll = long long ;
using pii = pair < int , int > ;
const static int _ = 1 << 20 ;
char fin[_] , * p1 = fin , * p2 = fin ;
inline char gc() { return (p1 == p2) && (p2 = (p1 = fin) + fread(fin , 1 , _ , stdin) , p1 == p2) ? EOF : * p1 ++ ; }
inline int read() {
	bool sign = 1 ; char c = 0 ; while(c < 48) ((c = gc()) == 45) && (sign = 0) ;
	int x = (c & 15) ; while((c = gc()) > 47) x = (x << 1) + (x << 3) + (c & 15) ;
	return sign ? x : -x ;
}
template < class T > void print(T x , char c = '\n') {
	(x == 0) && (putchar(48)) , (x < 0) && (putchar(45) , x = -x) ;
	static char _st[100] ; int _stp = 0 ;
	while(x) _st[++ _stp] = x % 10 ^ 48 , x /= 10 ;
	while(_stp) putchar(_st[_stp --]) ; putchar(c) ;
}
template < class T > void cmax(T & x , T y) { (x < y) && (x = y) ; }
template < class T > void cmin(T & x , T y) { (x > y) && (x = y) ; }

const int N = 1e5 + 5 ;
pii e[N << 1] ;
vector < int > vec[N << 2] ;
int n , m , t , fa[N] , sz[N] , d[N] , st[N] , top = 0 ;
int find(int x) {
	return x == fa[x] ? x : find(fa[x]) ;
}
inline int dis(int x) {
	int y = 0 ; 
	while(x ^ fa[x]) {
		y ^= d[x] ;
		x = fa[x] ;
	}
	return y ;
}
void add(int a , int b , int l , int r , int rt , int id) {
	if(a <= l && r <= b) {
		vec[rt].push_back(id) ;
		return ;
	}
	int mid = l + r >> 1 ;
	if(a <= mid) add(a , b , l , mid , rt << 1 , id) ;
	if(b > mid) add(a , b , mid + 1 , r , rt << 1 | 1 , id) ;
}
bool ok = 1 ;
void solve(int l , int r , int o) {
	const int tp = top ; const bool flag = ok ;
	for(auto id : vec[o]) {
		int u = find(e[id].first) ;
		int v = find(e[id].second) ;
		int du = dis(e[id].first) ;
		int dv = dis(e[id].second) ;
		if(u ^ v) {
			if(sz[u] < sz[v]) swap(u , v) ;
			fa[v] = u ;
			sz[u] += sz[v] ;
			d[v] = du ^ dv ^ 1 ;
			st[++ top] = v ;
		}
		else if((du ^ dv ^ 1) & 1) ok = 0 ;
	}
	if(l == r) {
		if(ok) puts("Yes") ; else puts("No") ;
	} else {
		int mid = l + r >> 1 ;
		solve(l , mid , o << 1) ;
		solve(mid + 1 , r , o << 1 | 1) ; 
	}
	ok = flag ;
	while(top ^ tp) { int u = st[top --] ; d[u] = 0 ; sz[fa[u]] -= sz[u] ; fa[u] = u ; }
}
signed main() {
#ifdef _WIN64
	freopen("testdata.in" , "r" , stdin) ;
#endif
	n = read() ; m = read() ; t = read() ;
	rep(i , 1 , m) {
		e[i].first = read() ;
		e[i].second = read() ;
		int l = read() , r = read() ;
		-- r ; add(l , r , 0 , t - 1 , 1 , i) ;
	}
	rep(i , 1 , n) { fa[i] = i ; sz[i] = 1 ; }
	solve(0 , t - 1 , 1) ;
	return 0 ;
}
posted @ 2019-12-19 14:48  _Isaunoya  阅读(191)  评论(0编辑  收藏  举报