标签: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