首页 > 代码库 > 省队集训Day1 睡觉困难综合征

省队集训Day1 睡觉困难综合征

传送门:https://www.luogu.org/problem/show?pid=3613

【题解】

按二进制位分开,对于每一位,用“起床困难综合征”的方法贪心做。

写棵LCT,维护正反两种权值,每个维护2种,代表全0的输出和全1的输出。

然后直接上LCT即可。

权值的合并有点trick,可以参考代码,需要压位。

技术分享
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 1e5 + 10;
const int mod = 1e9+7;

int n, m, K;

struct node {
    ull p0, p1;
    node () {}
    node (ull p0, ull p1) : p0(p0), p1(p1) {} 
    friend node operator + (node a, node b) {
        return node( (a.p0 & b.p1) | ((~a.p0) & b.p0), (a.p1 & b.p1) | ((~a.p1) & b.p0) );
    }
};

inline node deal(int op, ull x) {
    if(op == 1) return node(0, x);    
    if(op == 2) return node(x, ull(-1));
    if(op == 3) return node(x, ~x);
}

struct LCT {
    int ch[M][2], fa[M]; 
    bool rev[M];
    node w[M][2], val[M];
    # define ls ch[x][0]
    # define rs ch[x][1] 
    inline void up(int x) {
        if(!x) return ;
        w[x][0] = w[x][1] = val[x];
        if(ls) w[x][0] = w[ls][0] + w[x][0], w[x][1] = w[x][1] + w[ls][1];
        if(rs) w[x][0] = w[x][0] + w[rs][0], w[x][1] = w[rs][1] + w[x][1]; 
    }
    inline void pushrev(int x) {
        if(!x) return ;
        rev[x] ^= 1;
        swap(ch[x][0], ch[x][1]); 
        swap(w[x][0], w[x][1]);
    }
    inline void down(int x) {
        if(!x || !rev[x]) return ;
        pushrev(ls); pushrev(rs);
        rev[x] = 0;
    }
    # undef ls
    # undef rs
    inline bool isrt(int x) {
        return ch[fa[x]][0] != x && ch[fa[x]][1] != x; 
    }
    inline void rotate(int x) {
        int y = fa[x], z = fa[y], ls = ch[y][1] == x, rs = ls^1;
        if(!isrt(y)) ch[z][ch[z][1] == y] = x;
        fa[ch[x][rs]] = y, fa[y] = x, fa[x] = z;
        ch[y][ls] = ch[x][rs]; ch[x][rs] = y;
        up(y); up(x);
    }
    int st[M]; 
    inline void splay(int x) {
        int stn = 0, tx = x;
        while(!isrt(tx)) st[++stn] = tx, tx = fa[tx];
        st[++stn] = tx;
        for (int i=stn; i; --i) down(st[i]);
        while(!isrt(x)) {
            int y = fa[x], z = fa[y];
            if(!isrt(y)) {
                if((ch[z][0] == y)^(ch[y][0] == x)) rotate(x);
                else rotate(y);
            }
            rotate(x);
        }
    }
    
    inline int access(int x) {
        int t = 0;
        for (; x; t = x, x = fa[x]) {
            splay(x);
            ch[x][1] = t;
            up(x);
        }
        return t;
    }
    
    inline void makeroot(int x) {
        access(x); splay(x); pushrev(x);
    }
    
    inline void link(int x, int y) {
        makeroot(y); fa[y] = x; 
    }
}T;

# define bit(x, i) (((x) >> (i)) & 1) 

int main() {
//    freopen("sleep.in", "r", stdin);
//    freopen("sleep.out", "w", stdout);
    scanf("%d%d%d", &n, &m, &K); 
    for (int i=1, op; i<=n; ++i) {
        ull x;
        scanf("%d%llu", &op, &x); 
        T.val[i] = T.w[i][0] = T.w[i][1] = deal(op, x);
        T.ch[i][0] = T.ch[i][1] = T.fa[i] = T.rev[i] = 0; 
    }
    for (int i=1, u, v; i<n; ++i) {
         scanf("%d%d", &u, &v);
        T.link(u, v);
    }
    int op, x, y; ull z, tx, ty, ans, t;
    while(m--) {
        scanf("%d%d%d%llu", &op, &x, &y, &z);
        if(op == 1) {
            ans = 0; t = 0;
            T.makeroot(x); T.access(y); T.splay(y); 
            tx = T.w[y][0].p0, ty = T.w[y][0].p1; 
            for (int i=63; ~i; --i) {
                if(bit(tx, i)) ans |= (1ull << i); 
                else if(bit(ty, i)) {
                    if(t + (1ull << i) <= z) t = t + (1ull << i), ans |= (1ull << i);
                }
            }
            printf("%llu\n", ans); 
        } else {
            T.splay(x);
            T.val[x] = deal(y, z);
            T.up(x); 
        }
    }
    return 0;
}
View Code

 

省队集训Day1 睡觉困难综合征