线段树分治学习笔记
名字高大上其实好学的一批…
多处理一类问题…类如"一条边会在 [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 ;
}