zoukankan      html  css  js  c++  java
  • [Ynoi2017]由乃的OJ

    可以发现因为运算只有位运算,因此每一位是互不影响的,因此我们可以将每一位拉出来单独考虑。你会发现对于每一位而言,不论在何时都只有两种取值,并且一旦我们知道了这一位进入这条链的取值,最后出来的答案也是确定的。因此我们可以考虑直接维护出 (0 / 1) 进入这段链的取值,这个我们可以直接通过 (LCT) 来维护。具体来讲,对于 (Splay) 上的每个节点 (i) 维护出 (l_i, r_i),分别表示以 (0 / 1) 进入以 (i) 为根的 ( m Splay) 中的点组成的链(从深度浅的点到深度深的点),那么就有合并(令 (f_{i, 0}, f_{i, 1}) 分别表示以 (0 / 1) 进入 (i) 的答案):

    [l_i = (l_{ls} & r_{rs}) | ((sim l_{ls}) & l_{rs}) ]

    [r_i = (r_{ls} & r_{rs}) | ((sim r_{ls}) & l_{rs}) ]

    实现的时候因为 (LCT)(Makeroot) 操作,因此还要记录反向进入的答案。然后最终我们 (Split) 取出这条链,从高到低位贪心去选择即可,于此同时记录一个 (up) 表示有没有达到上界。这样复杂度就能做到 (O(nk log n))

    你会发现这个做法的瓶颈在于我们进行了拆位考虑,但你会发现我们只在乎每一位从 (0 / 1) 进入出来后的答案,又没有什么办法能让所有位置通过一次运算就知道 (0 / 1) 进入的答案呢?不难发现因为所有位是不会互相影响的,于是我们直接拿所有全 (0) 的二进制串和全 (1) 的二进制串进去跑即可,这样就可以一次跑出所有位置以 (0 / 1) 进入的答案了。因为每位之间不会互相影响,所以合并方式还是和按位考虑的时候一致。这样复杂度就是 (O(n imes max{k, log n})) 了。

    一些坑点:

    • 注意以后写 (LCT) 时,(pushdown) 一定是交换儿子的信息,而自己的信息在打标记时就要交换。因为 (Splay) 时会可能用到儿子的信息。
    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, l, r) for(int i = l; i <= r; ++i)
    #define dep(i, l, r) for(int i = r; i >= l; --i)
    #define Next(i, u) for(int i = h[u]; i; i = e[i].next)
    typedef unsigned long long ull;
    const int N = 100000 + 5;
    struct edge{
        int v, next;
    }e[N << 1];
    struct node{
        ull l, r;
        node operator + (const node &b){
            node a; 
            a.l = (~l & b.l) | (l & b.r), a.r = (~r & b.l) | (r & b.r);
            return a;
        }
    }res, f[N][2], val[N][2];
    ull x, ans, limit;
    int n, m, k, u, v, up, tot, opt, top, h[N], st[N], fa[N], tag[N], ch[N][2];
    int read(){
        char c; int x = 0, f = 1;
        c = getchar();
        while(c > '9' || c < '0'){ if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    void add(int u, int v){
        e[++tot].v = v, e[tot].next = h[u], h[u] = tot;
        e[++tot].v = u, e[tot].next = h[v], h[v] = tot;
    }
    void dfs(int u, int Fa){
        fa[u] = Fa;
        Next(i, u) if(e[i].v != Fa) dfs(e[i].v, u);
    }
    int which(int x){
        return (ch[fa[x]][1] == x);
    }
    int isroot(int x){
        return ((ch[fa[x]][0] != x) && (ch[fa[x]][1] != x)); 
    }
    void update(int x){
        val[x][0].l = 0, val[x][0].r = limit, val[x][1] = val[x][0];
        if(ch[x][0]) val[x][0] = val[ch[x][0]][0];
        if(ch[x][1]) val[x][1] = val[ch[x][1]][1];
        val[x][0] = val[x][0] + f[x][0], val[x][1] = val[x][1] + f[x][1];
        if(ch[x][1]) val[x][0] = val[x][0] + val[ch[x][1]][0];
        if(ch[x][0]) val[x][1] = val[x][1] + val[ch[x][0]][1];
    }
    void down(int x){
        if(!tag[x]) return;
        tag[x] = 0, tag[ch[x][0]] ^= 1, tag[ch[x][1]] ^= 1, swap(ch[x][0], ch[x][1]);
        swap(val[ch[x][0]][0], val[ch[x][0]][1]), swap(val[ch[x][1]][0], val[ch[x][1]][1]); // 就是指的这里
    }
    void rotate(int x){
        int y = fa[x], z = fa[y], k = which(x), w = ch[x][k ^ 1];
        fa[w] = y, ch[y][k] = w;
        fa[x] = z; if(!isroot(y)) ch[z][which(y)] = x;
        fa[y] = x, ch[x][k ^ 1] = y;
        update(y), update(x);
    }
    void Splay(int x){
        int cur = x; st[++top] = x;
        while(!isroot(cur)) st[++top] = fa[cur], cur = fa[cur];
        while(top) down(st[top--]);
        while(!isroot(x)){
            int y = fa[x];
            if(!isroot(y)){
                if(which(x) == which(y)) rotate(y);
                else rotate(x);
            }
            rotate(x);
        }
    }
    void Access(int x){
        for(int y = 0; x; y = x, x = fa[x]) Splay(x), ch[x][1] = y, update(x);
    }
    void Makeroot(int x){
        Access(x), Splay(x), tag[x] ^= 1, swap(val[x][0], val[x][1]); // 以及这里
    }
    void Split(int x, int y){
        Makeroot(x), Access(y), Splay(y);
    }
    signed main(){
        n = read(), m = read(), k = read(); 
        rep(i, 0, k - 1) limit += (1ull << i);
        rep(i, 1, n){
            opt = read(), scanf("%llu", &x);
            if(opt == 1) f[i][0].l = (0ull & x), f[i][0].r = (limit & x), f[i][1] = f[i][0];
            if(opt == 2) f[i][0].l = (0ull | x), f[i][0].r = (limit | x), f[i][1] = f[i][0];
            if(opt == 3) f[i][0].l = (0ull ^ x), f[i][0].r = (limit ^ x), f[i][1] = f[i][0];
            val[i][0] = f[i][0], val[i][1] = f[i][1];
        }
        rep(i, 1, n - 1) u = read(), v = read(), add(u, v);
        dfs(1, 0);
        while(m--){
            opt = read(), u = read(), v = read(), scanf("%llu", &x);
            if(opt == 1){
                Split(u, v), res = val[v][0], up = 1, ans = 0;
                dep(i, 0, k - 1){
                    if((1ull << i) <= x){
                        if(res.l & (1ull << i)) up = (up & (!(x & (1ull << i)))), ans += (1ull << i);
                        else if(res.r & (1ull << i)){
                            if(!up || (x & (1ull << i))) ans += (1ull << i);
                        }
                        else if(x & (1ull << i)) up = 0;
                    }
                    else if(res.l & (1ull << i)) ans += (1ull << i);
                }
                printf("%llu
    ", ans);
            }
            else{
                Splay(u);
                if(v == 1) f[u][0].l = (0ull & x), f[u][0].r = (limit & x), f[u][1] = f[u][0];
                if(v == 2) f[u][0].l = (0ull | x), f[u][0].r = (limit | x), f[u][1] = f[u][0];
                if(v == 3) f[u][0].l = (0ull ^ x), f[u][0].r = (limit ^ x), f[u][1] = f[u][0];
                update(u);
            }
        }
        return 0;
    }
    
    GO!
  • 相关阅读:
    mybatis 错误 Invalid bound statement (not found)
    Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
    bug 记录 Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans
    解决:The Tomcat connector configured to listen on port 8182 failed to start. The port may already be in use or the connector may be misconfigured.
    jquery validate 验证插件 解决多个相同的Name 只验证第一个的方案
    phpStorm+xdebug调试(php7.3)
    小程序视频多个视频播放与暂停
    CSS实现单行、多行文本溢出显示省略号(…)
    Packet for query is too large (4,544,730 > 4,194,304). You can change this value on the server by setting the 'max_allowed_packet' variable.
    idea自动在文件头中添加作者和创建时间
  • 原文地址:https://www.cnblogs.com/Go7338395/p/13661934.html
Copyright © 2011-2022 走看看