[IOI 2018] Werewolf
[题目链接]
https://www.luogu.org/problemnew/show/P4899
[算法]
建出原图的最小/最大生成树的kruskal重构树然后二维数点
时间复杂度 : O((N+Q)logN)
[代码]
#include<bits/stdc++.h> using namespace std; #define N 200010 #define M 400010 #define MAXLOG 20 typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); } template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } struct info { int x , y; } a[M]; struct edge { int to , nxt; } ea[N << 2] , eb[N << 2]; int n , m , q , tot , timera , timerb , cnta , cntb; int la[N << 1] , ra[N << 1] , fathera[N << 1][MAXLOG] , fatherb[N << 1][MAXLOG] , deptha[N << 1] , depthb[N << 1] , rt[N << 1] , heada[N << 1] , headb[N << 1] , lb[N << 1] , rb[N << 1] , fa[N << 1] , valuea[N << 1] , valueb[N << 1] , w[N << 1]; struct Presitent_Segment_Tree { int sz; Presitent_Segment_Tree() { sz = 0; } struct node { int lc , rc; int cnt; } a[N * 60]; inline void modify(int &now , int old , int l , int r , int x , int value) { now = ++sz; a[now].lc = a[old].lc , a[now].rc = a[old].rc; a[now].cnt = a[old].cnt + value; if (l == r) return; int mid = (l + r) >> 1; if (mid >= x) modify(a[now].lc , a[old].lc , l , mid , x , value); else modify(a[now].rc , a[old].rc , mid + 1 , r , x , value); } inline int query(int rt1 , int rt2 , int l , int r , int ql , int qr) { if (l == ql && r == qr) return a[rt1].cnt - a[rt2].cnt; int mid = (l + r) >> 1; if (mid >= qr) return query(a[rt1].lc , a[rt2].lc , l , mid , ql , qr); else if (mid + 1 <= ql) return query(a[rt1].rc , a[rt2].rc , mid + 1 , r , ql , qr); else return query(a[rt1].lc , a[rt2].lc , l , mid , ql , mid) + query(a[rt1].rc , a[rt2].rc , mid + 1 , r , mid + 1 , qr); } } PST; inline void addedgea(int u , int v) { ++tot; ea[tot] = (edge){v , heada[u]}; heada[u] = tot; } inline void addedgeb(int u , int v) { ++tot; eb[tot] = (edge){v , headb[u]}; headb[u] = tot; } inline void dfsa(int u , int par) { fathera[u][0] = par; deptha[u] = deptha[par] + 1; for (int i = 1; i < MAXLOG; i++) fathera[u][i] = fathera[fathera[u][i - 1]][i - 1]; la[u] = ++timera; for (int i = heada[u]; i; i = ea[i].nxt) { int v = ea[i].to; if (v == par) continue; dfsa(v , u); } ra[u] = timera; } inline void dfsb(int u , int par) { fatherb[u][0] = par; depthb[u] = depthb[par] + 1; for (int i = 1; i < MAXLOG; i++) fatherb[u][i] = fatherb[fatherb[u][i - 1]][i - 1]; lb[u] = ++timerb; for (int i = headb[u]; i; i = eb[i].nxt) { int v = eb[i].to; if (v == par) continue; dfsb(v , u); } rb[u] = timerb; } inline bool cmpa(info a , info b) { return min(a.x , a.y) > min(b.x , b.y); } inline bool cmpb(info a , info b) { return max(a.x , a.y) < max(b.x , b.y); } inline int getroot(int x) { if (fa[x] == x) return x; else return fa[x] = getroot(fa[x]); } inline void kruskalA() { int tot = 0; cnta = n; timera = 0; sort(a + 1 , a + m + 1 , cmpa); for (int i = 1; i <= 2 * n; i++) fa[i] = i; for (int i = 1; i <= m; i++) { int fu = getroot(a[i].x) , fv = getroot(a[i].y); if (fu != fv) { ++cnta; addedgea(cnta , fu); addedgea(cnta , fv); valuea[cnta] = min(a[i].x , a[i].y); fa[fu] = fa[fv] = fa[cnta] = cnta; ++tot; } if (tot == n - 1) break; } dfsa(cnta , 0); } inline void kruskalB() { int tot = 0; cntb = n; timerb = 0; sort(a + 1 , a + m + 1 , cmpb); for (int i = 1; i <= 2 * n; i++) fa[i] = i; for (int i = 1; i <= m; i++) { int fu = getroot(a[i].x) , fv = getroot(a[i].y); if (fu != fv) { ++cntb; addedgeb(cntb , fu); addedgeb(cntb , fv); valueb[cntb] = max(a[i].x , a[i].y); fa[fu] = fa[fv] = fa[cntb] = cntb; ++tot; } if (tot == n - 1) break; } dfsb(cntb , 0); } inline bool query(int l1 , int r1 , int l2 , int r2) { return PST.query(rt[r1] , rt[l1 - 1] , 1 , 2 * n , l2 , r2); } int main() { read(n); read(m); read(q); for (int i = 1; i <= m; i++) { read(a[i].x); read(a[i].y); ++a[i].x; ++a[i].y; } kruskalA(); kruskalB(); for (int i = 1; i <= n; i++) w[la[i]] = lb[i]; for (int i = 1; i <= 2 * n; i++) PST.modify(rt[i] , rt[i - 1] , 1 , 2 * n , w[i] , 1); for (int i = 1; i <= q; i++) { int s , e , l , r; read(s); read(e); read(l); read(r); ++s; ++e; ++l; ++r; if (s < l || e > r) { puts("0"); continue; } for (int i = MAXLOG - 1; i >= 0; i--) if (fathera[s][i] && valuea[fathera[s][i]] >= l) s = fathera[s][i]; for (int i = MAXLOG - 1; i >= 0; i--) if (fatherb[e][i] && valueb[fatherb[e][i]] <= r) e = fatherb[e][i]; if (query(la[s] , ra[s] , lb[e] , rb[e])) puts("1"); else puts("0"); } return 0; }