标签:bzoj3668 综合症 struct main ash tmp ref 时间复杂度 highlight
题目描述
输入
输出
样例输入
5 5 3
1 7
2 6
3 7
3 6
3 1
1 2
2 3
3 4
1 5
1 1 4 7
1 1 3 5
2 1 1 3
2 3 3 3
1 1 3 2
样例输出
7
1
5
题解
树链剖分+线段树区间合并
前置技能:【bzoj3668】[Noi2014]起床困难综合症。
对于这道题——那道签到题的加强版,如何想办法拿出树上的一条链时关键。
考虑树剖,并使用线段树区间合并来处理一段区间从左到右&从右到左方向0&1会变成什么。
这样时间复杂度为$O(nk\log^2n)$,会TLE。
考虑:没有必要对二进制的每一位开一棵线段树,而是维护一棵线段树,记录000...00(2)和111..11(2)会变成什么。
然后区间合并复杂度同样是$O(1)$的,并且可以直接拿出区间每一位的信息。
具体实现上,要注意x->y方向和y->x方向是不同的,因此需要分开处理。
最后按照起床困难综合症的方法贪心即可。
时间复杂度为$O(n(\log^2n+k))$。
#include <cstdio> #include <cstring> #include <algorithm> #define N 100010 #define lson l , mid , x << 1 #define rson mid + 1 , r , x << 1 | 1 using namespace std; typedef unsigned long long ull; const ull inf = 0xffffffffffffffffll; struct data { ull l0 , l1 , r0 , r1; data() {}; data(ull L0 , ull L1 , ull R0 , ull R1) {l0 = L0 , l1 = L1 , r0 = R0 , r1 = R1;} }a[N << 2] , tmp; int n , head[N] , to[N << 1] , next[N << 1] , cnt , fa[N] , deep[N] , bl[N] , si[N] , pos[N] , tot , opt[N] , kind[N]; ull v[N] , w[N]; void add(int x , int y) { to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt; } void dfs1(int x) { int i; si[x] = 1; for(i = head[x] ; i ; i = next[i]) if(to[i] != fa[x]) fa[to[i]] = x , deep[to[i]] = deep[x] + 1 , dfs1(to[i]) , si[x] += si[to[i]]; } void dfs2(int x , int c) { int i , k = 0; bl[x] = c , pos[x] = ++tot , kind[tot] = opt[x] , w[tot] = v[x]; for(i = head[x] ; i ; i = next[i]) if(to[i] != fa[x] && si[to[i]] > si[k]) k = to[i]; if(k) { dfs2(k , c); for(i = head[x] ; i ; i = next[i]) if(to[i] != fa[x] && to[i] != k) dfs2(to[i] , to[i]); } } data rev(data a) { return data(a.r0 , a.r1 , a.l0 , a.l1); } data merge(data a , data b) { return data((a.l0 & b.l1) | (~a.l0 & b.l0) , (a.l1 & b.l1) | (~a.l1 & b.l0) , (b.r0 & a.r1) | (~b.r0 & a.r0) , (b.r1 & a.r1) | (~b.r1 & a.r0)); } void build(int l , int r , int x) { if(l == r) { switch(kind[l]) { case 1: a[x].l0 = a[x].r0 = 0 , a[x].l1 = a[x].r1 = w[l]; break; case 2: a[x].l0 = a[x].r0 = w[l] , a[x].l1 = a[x].r1 = inf; break; default: a[x].l0 = a[x].r0 = w[l] , a[x].l1 = a[x].r1 = inf ^ w[l]; } return; } int mid = (l + r) >> 1; build(lson) , build(rson); a[x] = merge(a[x << 1] , a[x << 1 | 1]); } void update(int p , int opt , ull v , int l , int r , int x) { if(l == r) { switch(opt) { case 1: a[x].l0 = a[x].r0 = 0 , a[x].l1 = a[x].r1 = v; break; case 2: a[x].l0 = a[x].r0 = v , a[x].l1 = a[x].r1 = inf; break; default: a[x].l0 = a[x].r0 = v , a[x].l1 = a[x].r1 = inf ^ v; break; } return; } int mid = (l + r) >> 1; if(p <= mid) update(p , opt , v , lson); else update(p , opt , v , rson); a[x] = merge(a[x << 1] , a[x << 1 | 1]); } data query(int b , int e , int l , int r , int x) { if(b <= l && r <= e) return a[x]; int mid = (l + r) >> 1; if(e <= mid) return query(b , e , lson); else if(b > mid) return query(b , e , rson); else return merge(query(b , e , lson) , query(b , e , rson)); } data solve(int x , int y) { data px = data(0 , inf , 0 , inf) , py = px; while(bl[x] != bl[y]) { if(deep[bl[x]] > deep[bl[y]]) px = merge(px , rev(query(pos[bl[x]] , pos[x] , 1 , n , 1))) , x = fa[bl[x]]; else py = merge(query(pos[bl[y]] , pos[y] , 1 , n , 1) , py) , y = fa[bl[y]]; } if(deep[x] < deep[y]) py = merge(query(pos[x] , pos[y] , 1 , n , 1) , py); else px = merge(px , rev(query(pos[y] , pos[x] , 1 , n , 1))); return merge(px , py); } int main() { int m , i , q , x , y; ull j , z , ans; scanf("%d%d%*d" , &n , &m); for(i = 1 ; i <= n ; i ++ ) scanf("%d%llu" , &opt[i] , &v[i]); for(i = 1 ; i < n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x); dfs1(1) , dfs2(1 , 1); build(1 , n ,1); while(m -- ) { scanf("%d%d%d%llu" , &q , &x , &y , &z); if(q == 1) { tmp = solve(x , y) , ans = 0; for(j = 1ull << 63 ; j ; j >>= 1) { if(z >= j && tmp.l1 & j && !(tmp.l0 & j)) ans += j , z -= j; else ans += tmp.l0 & j; } printf("%llu\n" , ans); } else update(pos[x] , y , z , 1 , n , 1); } return 0; }
【bzoj4811】[Ynoi2017]由乃的OJ 树链剖分+线段树区间合并
标签:bzoj3668 综合症 struct main ash tmp ref 时间复杂度 highlight
原文地址:http://www.cnblogs.com/GXZlegend/p/7355908.html