• P7073 表达式(expr)


    说在前面

    考场上的我是真的逊,expr代码都写出来了结果没有更新到D:/submit而爆零。

    题意简述

    给你一个后缀表达式(s),只有&,|,!运算,有(n)个变量,为(x_1,x_2,cdots x_n),其中任意(x_i in {0,1}),给(x_i)的初值,(q)个操作,每次操作:

    给一个整数(a),要求将(x_a)的值取反,求这个表达式的值。

    数据范围:

    • (20\%) 运算仅有&|
    • 另外(30\%) (|s| le 1000,q le 1000,n le 1000)
    • 另外(20\%),变量初值全部相同。
    • (100\%) (1 le |s| le 1 imes 10 ^ 6,1 le q le 1 imes 10 ^ 5,2 le n le 1 imes 10 ^ 5)

    简单口胡

    • (20\%) 每次进行表达式运算,(mathcal{O}(nq)),逊

    部分分只会这一个

    正解:考虑对(x_i)取反是否会影响整个式子的值,先建一个表达式树,对于每个节点,它和它的子树也是一个表达式,其中对于非叶节点,这个节点是一个运算符,这个表达式的值为(L(x) operatorname{opt} R(x)),(operatorname{opt}) 为这个运算符,(L(x))(R(x))为这个节点的左子树表达式的值和右子树表达式的值。

    分类讨论:

    • 如果这个节点是叶子,啥事没有
    • 如果这个节点是&,那么:
      如果(L(x) = 0),那么这个表达式的值肯定为(0),也就是说(R(x))对答案没有贡献,给右子树里的所有节点打上标记。

    (R(x) = 0)同理。

    • 如果这个节点是|,那么:
      如果(L(x) = 1),那么这个表达式的值肯定为(1),也就是说(R(x))对答案没有贡献,给右子树里的所有节点打上标记。

    (R(x) = 1)同理。

    于是这题就没了,( ext{dfs})打好标记和计算一开始表达式的答案(ans),对于每一个询问,如果这个询问有标记,代表对其取反对(ans)没有变化,否则输出(!ans)

    大概是(mathcal{O}(n))

    # include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e6 + 5;
    int q[N],tot;
    int n,val[N / 10];
    
    int ch[N][2];
    bool C[N / 10];
    int Opt[N];
    
    stack <int> s;
    
    int Get(string st,int l)
    {
        int ans = 0;
        int len = st.size();
        for(int i = l; i < len; i++)
        {
            ans = ans * 10 + st[i] - '0';
        }
        return ans;
    }
    
    int key(char opt)
    {
        if(opt == '|') return -1;
        if(opt == '&') return -2;
        if(opt == '!') return -3;
    }
    
    void Input(void)
    {
        string st;
        while(cin >> st)
        {
            if(isdigit(st[0]))
            {
                break;
            }
            else
            {
                if(st[0] == 'x')
                {
                    int num = Get(st,1);
                    // printf("num = %d
    ",num);
                    q[++tot] = num;
                }
                else
                {
                    q[++tot] = key(st[0]);
                }
            }
        }
        n = Get(st,0);
        // printf("n = %d
    ",n);
        for(int i = 1; i <= n; i++)
        {
            scanf("%d",&val[i]);
        }
        return;
    }
    
    int dfs(int root)
    {
        if(root <= n) return val[root];
        if(Opt[root] == -3) return !dfs(ch[root][0]);
        if(Opt[root] == -1)  // or
        {
            int ans1 = dfs(ch[root][0]),ans2 = dfs(ch[root][1]);
            if(ans1 == 1) 
                C[ch[root][1]] = 1;
            if(ans2 == 1) 
                C[ch[root][0]] = 1;
            return ans1 | ans2;
        }
        else
        {
            if(Opt[root] == -2) // and
            {
                int ans1 = dfs(ch[root][0]),ans2 = dfs(ch[root][1]);
                if(ans1 == 0) 
                    C[ch[root][1]] = 1;
                if(ans2 == 0)
                    C[ch[root][0]] = 1;
                return ans1 & ans2;
            }
        }
    }
    
    void pushup(int root)
    {
        if(ch[root][0]) C[ch[root][0]] |= C[root];
        if(ch[root][1]) C[ch[root][1]] |= C[root];
        if(ch[root][0]) pushup(ch[root][0]);
        if(ch[root][1]) pushup(ch[root][1]);
        return;
    }
    
    int main(void)
    {
        Input();
        int cur = n;
        for(int i = 1; i <= tot; i++)
        {
            if(q[i] > 0)
            {
                s.push(q[i]);
            }
            else
            {
                if(q[i] == -3)
                {
                    int a1 = s.top();s.pop();
                    Opt[++cur] = -3;
                    ch[cur][0] = a1;
                    s.push(cur);
                    continue;
                }
                int a1 = s.top();s.pop();
                int a2 = s.top();s.pop();
                Opt[++cur] = q[i];
                ch[cur][0] = a1,ch[cur][1] = a2;
                s.push(cur);
            }
        }
        // printf("cur = %d
    ",cur);
        int now = dfs(cur);
        pushup(cur);
        int test;
        scanf("%d",&test);
        while(test--)
        {
            int x;
            scanf("%d",&x);
            printf("%d
    ",C[x] ? now : !now);
        }
        return 0;
    }
    
  • 相关阅读:
    JavaScript中的memorizing技术
    在IE6/7/8下识别html5标签
    JavaScript中的类式继承和原型式继承
    OpenSUSE环境配置
    CentOS环境配置(LNMP)
    CentOS上OpenCC中文简繁体转换
    jQuery点击按钮页面滚动条向下滚动
    javascript-数组常用方法
    Tomcat配置常见错误问题解决方法
    字符串
  • 原文地址:https://www.cnblogs.com/luyiming123blog/p/P7073.html
Copyright © 2020-2023  润新知