弱化版: [NOI2014] 起床困难综合症
求出每一位初始是 0/1 的结果
- 若 0 的结果为 1 ,直接加上该位贡献
- 若 1 的结果为 1 ,若该位填 1 不会超过最大值,那么填 1
注意到每位相互独立,可以压位进行计算
回到原问题,根据上述做法不难想到用 线段树+树剖 维护链上第 \(i\) 位 正序/逆序 操作后初始为 0/1 的结果,然后使用上述贪心。
合并左右区间大概是这样: \(fs[i][0][1]=fr[i][0][fl[i][0][1]]\)
这样做复杂度为 \(\mathcal O(nk \log^2 n)\),瓶颈在于合并时无法像上面一样压位。
但是可能的 \(fl\) 的取值只有 0/1 ,那么 \(0\) 进 \(1\) 出我们可以表示为:
这种位运算的形式使得我们可以压位,同理可得到其它转移,这里就不赘述了。
复杂度 \(\mathcal O(n \log^2 n)\) , 挺有意思的
#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define ull unsigned long long
#define pii pair< ull , int >
#define fi first
#define sc second
#define mp make_pair
const int MAXN = 1e5;
int n , m , k; pii val[ MAXN + 5 ];
vector< int > Graph[ MAXN + 5 ];
int fa[ MAXN + 5 ] , hs[ MAXN + 5 ] , dep[ MAXN + 5 ] , siz[ MAXN + 5 ];
void dfs1( int u , int fat ) {
fa[ u ] = fat; dep[ u ] = dep[ fat ] + 1; siz[ u ] = 1;
for( int v : Graph[ u ] ) if( v != fa[ u ] ) {
dfs1( v , u ); siz[ u ] += siz[ v ];
if( siz[ hs[ u ] ] < siz[ v ] ) hs[ u ] = v;
}
}
int tim , dfn[ MAXN + 5 ] , rk[ MAXN + 5 ] , top[ MAXN + 5 ];
void dfs2( int u , int tp ) {
dfn[ u ] = ++ tim , rk[ tim ] = u; top[ u ] = tp;
if( hs[ u ] ) dfs2( hs[ u ] , tp );
for( int v : Graph[ u ] ) if( v != fa[ u ] && v != hs[ u ] ) dfs2( v , v );
}
ull op( bool a , bool b , int op ) {
if( op == 1 ) return a & b;
if( op == 2 ) return a | b;
if( op == 3 ) return a ^ b;
}
struct node {
ull a[ 2 ][ 2 ];
node operator + ( const node &o ) const {
node r;
r.a[ 0 ][ 0 ] = ( a[ 0 ][ 0 ] & o.a[ 0 ][ 1 ] ) | ( ( ~a[ 0 ][ 0 ] ) & o.a[ 0 ][ 0 ] );
r.a[ 0 ][ 1 ] = ( a[ 0 ][ 1 ] & o.a[ 0 ][ 1 ] ) | ( ( ~a[ 0 ][ 1 ] ) & o.a[ 0 ][ 0 ] );
r.a[ 1 ][ 0 ] = ( o.a[ 1 ][ 0 ] & a[ 1 ][ 1 ] ) | ( ( ~o.a[ 1 ][ 0 ] ) & a[ 1 ][ 0 ] );
r.a[ 1 ][ 1 ] = ( o.a[ 1 ][ 1 ] & a[ 1 ][ 1 ] ) | ( ( ~o.a[ 1 ][ 1 ] ) & a[ 1 ][ 0 ] );
return r;
}
};
struct Segment_Tree {
node Tree[ 4 * MAXN + 5 ];
#define ls x << 1
#define rs x << 1 | 1
#define mid ( l + r >> 1 )
void Build( int x , int l = 1 , int r = n ) {
if( l == r ) {
for( int i = 0 ; i < k ; i ++ ) {
Tree[ x ].a[ 0 ][ 0 ] |= op( ( val[ rk[ l ] ].fi >> i ) & 1 , 0 , val[ rk[ l ] ].sc ) << i;
Tree[ x ].a[ 1 ][ 0 ] |= op( ( val[ rk[ l ] ].fi >> i ) & 1 , 0 , val[ rk[ l ] ].sc ) << i;
Tree[ x ].a[ 0 ][ 1 ] |= op( ( val[ rk[ l ] ].fi >> i ) & 1 , 1 , val[ rk[ l ] ].sc ) << i;
Tree[ x ].a[ 1 ][ 1 ] |= op( ( val[ rk[ l ] ].fi >> i ) & 1 , 1 , val[ rk[ l ] ].sc ) << i;
}
return;
}
Build( ls , l , mid ); Build( rs , mid + 1 , r );
Tree[ x ] = Tree[ ls ] + Tree[ rs ];
}
void Update( int x , int pos , int l = 1 , int r = n ) {
if( pos < l || pos > r ) return;
if( l == r ) {
Tree[ x ].a[ 0 ][ 0 ] = Tree[ x ].a[ 1 ][ 0 ] = Tree[ x ].a[ 0 ][ 1 ] = Tree[ x ].a[ 1 ][ 1 ] = 0;
for( int i = 0 ; i < k ; i ++ ) {
Tree[ x ].a[ 0 ][ 0 ] |= op( ( val[ rk[ l ] ].fi >> i ) & 1 , 0 , val[ rk[ l ] ].sc ) << i;
Tree[ x ].a[ 1 ][ 0 ] |= op( ( val[ rk[ l ] ].fi >> i ) & 1 , 0 , val[ rk[ l ] ].sc ) << i;
Tree[ x ].a[ 0 ][ 1 ] |= op( ( val[ rk[ l ] ].fi >> i ) & 1 , 1 , val[ rk[ l ] ].sc ) << i;
Tree[ x ].a[ 1 ][ 1 ] |= op( ( val[ rk[ l ] ].fi >> i ) & 1 , 1 , val[ rk[ l ] ].sc ) << i;
}
return;
}
Update( ls , pos , l , mid ); Update( rs , pos , mid + 1 , r );
Tree[ x ] = Tree[ ls ] + Tree[ rs ];
}
node Query( int x , int ql , int qr , int l = 1 , int r = n ) {
if( ql <= l && r <= qr ) return Tree[ x ];
if( qr <= mid ) return Query( ls , ql , qr , l , mid );
if( ql > mid ) return Query( rs , ql , qr , mid + 1 , r );
return Query( ls , ql , qr , l , mid ) + Query( rs , ql , qr , mid + 1 , r );
}
}Tr;
ull Query( int u , int v , ull mxw ) {
node l , r , s; bool lf = 0 , rf = 0;
while( top[ u ] != top[ v ] ) {
if( dep[ top[ u ] ] < dep[ top[ v ] ] ) { //v
node p = Tr.Query( 1 , dfn[ top[ v ] ] , dfn[ v ] );
if( !rf ) r = p , rf = 1; else r = p + r;
v = fa[ top[ v ] ];
}
else { //u
node p = Tr.Query( 1 , dfn[ top[ u ] ] , dfn[ u ] );
if( !lf ) l = p , lf = 1; else l = p + l;
u = fa[ top[ u ] ];
}
}
if( dep[ u ] < dep[ v ] ) {
node p = Tr.Query( 1 , dfn[ u ] , dfn[ v ] );
if( !rf ) r = p , rf = 1; else r = p + r;
}
else {
node p = Tr.Query( 1 , dfn[ v ] , dfn[ u ] );
if( !lf ) l = p , lf = 1; else l = p + l;
}
swap( l.a[ 0 ] , l.a[ 1 ] );
if( lf && rf ) s = l + r;
if( !lf ) s = r; if( !rf ) s = l;
ull Ans = 0;
for( int i = k - 1 ; i >= 0 ; i -- ) {
if( ( s.a[ 0 ][ 0 ] >> i ) & 1 ) Ans += 1llu << i;
else if( ( ( s.a[ 0 ][ 1 ] >> i ) & 1 ) && mxw >= ( 1llu << i ) ) { mxw -= 1llu << i , Ans += 1llu << i; }
}
return Ans;
}
int main( ) {
scanf("%d %d %d",&n,&m,&k);
for( int i = 1 ; i <= n ; i ++ ) scanf("%d %llu",&val[ i ].sc,&val[ i ].fi);
for( int i = 1 , u , v ; i < n ; i ++ ) {
scanf("%d %d",&u,&v);
Graph[ u ].push_back( v );
Graph[ v ].push_back( u );
}
dfs1( 1 , 0 ); dfs2( 1 , 1 ); Tr.Build( 1 );
for( int i = 1 , op , x , y ; i <= m ; i ++ ) {
ull z; scanf("%d %d %d %llu",&op,&x,&y,&z);
if( op == 1 ) printf("%llu\n", Query( x , y , z ) );
if( op == 2 ) val[ x ] = mp( z , y ) , Tr.Update( 1 , dfn[ x ] );
}
return 0;
}