1. 程式人生 > >線段樹開新坑:kuangbin帶你飛

線段樹開新坑:kuangbin帶你飛

寫在最前面的廢話

這裡I以前的題是暑假剛剛開始的時候在家寫的,然後多校一波就荒廢了

9月開頭回家一波,重新填坑,= =,kuangbin帶你飛的pdf,這才一半題,後面還有一波,藍瘦,慢慢寫吧,不寫題怎麼變的更強

單點更新

cmy曾經這題瘋狂TLE

後來發現是因為cin的原因,cin好慢的說

樹狀陣列也可以做,zkw的暴力單點修改也可加速一波

樹狀陣列

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
using namespace
std; const int N=50500; int tree[N],n,x,y; string st; void add(int k,int num){ while (k<=n){ tree[k]+=num; k+=k&-k; } } int read(int k){ int sum=0; while (k){ sum+=tree[k]; k-=k&-k; } return sum; } int main(){ int T;scanf("%d",&T); for
(int cas=1;cas<=T;cas++){ scanf("%d",&n); memset(tree,0,sizeof(tree)); for (int i=1;i<=n;i++){ scanf("%d",&x); add(i,x); } scanf("\n"); printf("Case %d:\n",cas); int k=0; for (;cin>>st&&st[0
]!='E';){ scanf("%d%d",&x,&y); if (st[0]=='Q') printf("%d\n",read(y)-read(x-1)); else if (st[0]=='A')add(x,y); else add(x,-y); } } return 0; }

暴力單點修改

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2e5 + 7;

struct segmentTree
{
    #define lc (t<<1)
    #define rc (t<<1^1)
    int sum[N], M;

    inline void build(int n){
        M = 1;
        for (;M < n;) M <<= 1;
        M--;
        memset(sum, sizeof(sum), 0);
        for (int i = 1+M; i <= n+M; i++){
            scanf("%d", &sum[i]);
        }
        for (int t = M; t >= 1; t--){
            sum[t] = sum[lc] + sum[rc];
        }
    }

    void add(int t, int x){
        for (sum[t+=M]+=x, t>>=1; t; t>>=1){
            sum[t] = sum[lc] + sum[rc];
        }
    }

    int query(int l, int r){
        int ans = 0;
        for (l+=M-1,r+=M+1; l^r^1; l>>=1,r>>=1){
            if (~l&1) ans += sum[l^1];
            if ( r&1) ans += sum[r^1];
        }
        return ans;
    }
} T;

int main(){
    //freopen("in.txt", "r", stdin);
    int _, n, x, y; 
    scanf("%d", &_);
    for (int __ = 1; __<=_;__++){
        printf("Case %d:\n", __);
        scanf("%d", &n);
        T.build(n);
        getchar();
        string st;
        for (;cin >> st && st[0] != 'E';){
            scanf("%d%d", &x, &y);
            if (st[0] == 'A'){
                T.add(x, y);
            }else if (st[0] == 'S'){
                T.add(x, -y);
            }else{
                printf("%d\n", T.query(x, y));
            }
        }
    }
}

把上面的程式碼改幾行

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 8e5 + 7;

struct segmentTree
{
    #define lc (t<<1)
    #define rc (t<<1^1)
    int ma[N], M;

    inline void build(int n){
        M = 1;
        for (;M < n;) M <<= 1;
        M--;
        memset(ma, sizeof(ma), 0);
        for (int i = 1+M; i <= n+M; i++){
            scanf("%d", &ma[i]);
        }
        for (int t = M; t >= 1; t--){
            ma[t] = max(ma[lc], ma[rc]);
        }
    }

    void update(int t, int x){
        for (ma[t+=M] = x, t>>=1; t; t>>=1){
            ma[t] = max(ma[lc], ma[rc]);
        }
    }

    int query(int l, int r){
        int ans = 0;
        for (l+=M-1,r+=M+1; l^r^1; l>>=1,r>>=1){
            if (~l&1) ans = max(ans, ma[l^1]);
            if ( r&1) ans = max(ans, ma[r^1]);
        }
        return ans;
    }
} T;

int main(){
    //freopen("in.txt", "r", stdin);
    int _, n, m, x, y; 
    for (;~scanf("%d%d", &n, &m);){        
        T.build(n);
        string st;
        for (;m--;){
            cin >>st;
            scanf("%d%d", &x, &y);
            if (st[0] == 'U'){
                T.update(x, y);
            }else{
                printf("%d\n", T.query(x, y));
            }
        }
    }
}

樹狀陣列舒服

數字插入按順序插入對應的位置,然後看這個位置後面有多少個數就有多少逆序對

單點修改,區間求和

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 7;

struct binaryIndexTree
{
    int val[N], n;

    inline void init(int n){
        this->n = n;
        memset(val, 0, sizeof(val));
    }

    inline void add(int k, int num){
        for (;k <= n;){
            val[k] += num;
            k += k&-k;
        }
    }

    inline int sum(int k){
        int sum = 0;
        for (;k;){
            sum += val[k];
            k -= k&-k;
        }
        return sum;
    }
} T;

int arr[N], n;

int main()
{
    //freopen("in.txt", "r", stdin); 
    for (;~scanf("%d", &n);){
        T.init(n);
        int sum = 0;
        for (int i = 0; i < n; i++){
            scanf("%d", &arr[i]);
            arr[i]++;
            sum += T.sum(n) - T.sum(arr[i] - 1);
            T.add(arr[i], 1);
        }
        int ans = sum;
        for (int i = 0; i < n; i++){
            sum += (n - arr[i]) - (arr[i] - 1);
            ans = min(ans, sum);
        }
        printf("%d\n", ans);
    }
}

注意:h = min(h, n);

單點查詢區間最大值,查詢修改一體

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6 + 7;

struct segmentTree
{
    #define lc (rt<<1)
    #define rc (rt<<1^1)
    #define lson l, mid, rt<<1
    #define rson mid+1, r, rt<<1^1
    int val[N], M; // M: num of non-leaf nodes
    // have an index of the array x
    // x + M is the index of it in the tree

    inline void build(int n, int w){
        M = 1; while(M<n) M<<=1; M--;
        // leaf nodes with values
        for (int leaf = 1+M; leaf <= n+M; leaf++){
            val[leaf] = w;
        }
        // leaf nodes which is null
        for (int leaf = n+1+M; leaf <= (M<<1^1); leaf++){
            val[leaf] = 0;
        }
        // non-leaf nodes(include root)
        for (int rt = M; rt >= 1; rt--){
            val[rt] = max(val[lc], val[rc]);
        }
    }

    inline void pushUp(int rt){
        val[rt] = max(val[lc], val[rc]);
    }

    inline int query(int x, int rt){
        if (rt > M){
            val[rt] -= x;
            return rt - M;
        }
        int ans = (val[lc] >= x) ? query(x, lc) : query(x, rc);
        pushUp(rt);
        return ans;
    }
} T;

int main(){
    //freopen("in.txt", "r", stdin);
    int n, h, w, x; 
    for (;~scanf("%d%d%d", &h, &w, &n);){      
        h = min(h, n);
        T.build(h, w);
        for (;n--;){
            scanf("%d", &x);
            if (T.val[1] < x) puts("-1");
            else printf("%d\n", T.query(x, 1));
        }
    }
    return 0;
}

跟上題很像,查詢修改一體

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6 + 7;

int ans[N], pos[N], jump[N];

struct segmentTree
{
    #define lc (rt<<1)
    #define rc (rt<<1^1)
    #define lson l, mid, rt<<1
    #define rson mid+1, r, rt<<1^1
    int val[N], M; // M: num of non-leaf nodes
    // have an index of the array x
    // x + M is the index of it in the tree

    inline void build(int n){
        M = 1; while(M<n) M<<=1; M--;
        // leaf nodes with values
        for (int leaf = 1+M; leaf <= n+M; leaf++){
            val[leaf] = 1;
        }
        // leaf nodes which is null
        for (int leaf = n+1+M; leaf <= (M<<1^1); leaf++){
            val[leaf] = 0;
        }
        // non-leaf nodes(include root)
        for (int rt = M; rt >= 1; rt--){
            val[rt] = val[lc] + val[rc];
        }
    }

    inline void pushUp(int rt){
        val[rt] = val[lc] + val[rc];
    }

    inline void update(int pos, int jump, int rt){
        if (rt > M){
            val[rt]--;
            ans[rt-M] = jump;
            return;
        }
        if (val[lc] >= pos) update(pos, jump, lc);
        else update(pos-val[lc], jump, rc);
        pushUp(rt);
    }
} T;

int main(){
    //freopen("in.txt", "r", stdin);
    int n;
    for (;~scanf("%d", &n);){
        T.build(n);
        for (int i = 1; i <= n; i++){
            scanf("%d %d", &pos[i], &jump[i]);
            pos[i]++;
        }
        for (int i = n; i >= 1; i--){
            T.update(pos[i], jump[i], 1);
        }
        for (int i = 1; i < n; i++){
            printf("%d ", ans[i]);
        }
        printf("%d\n", ans[n]);
    }
    return 0;
}

題意:

n個熊孩子每個人有個數字a[i],首先k號熊孩子出圈,然後第k+a[i]個熊孩子出圈,一個環,可以繞很多圈,如果a[i]為正則順時針數,反之逆時針,相當於一個變體的約瑟夫遊戲,第i個出圈的熊孩子,有f[i]的得分,f[i]為i的因子個數
反正沒人看的講解:

分為兩個部分:線段樹模擬約瑟夫遊戲+尋找1到n範圍內因數數量最多的那個ans,約瑟夫遊戲只要做到第ans個人出圈就好了

區間和的線段樹,每個葉子節點為1,代表一個熊孩子,出圈置為0,

至於因子數量,my math is very poor,所以我搜了題解,看見標題裡一群反素數,於是順勢百度了反素數,搜到反素數深度分析,第三道題正好就是這玩意,於是複製貼上之(劃掉),雖然到現在還不知道反素數是個什麼玩意

似乎搜到的題解都是打表來解決的因數個數問題,

我真的debug了10個小時,心累

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e7 + 7;
const LL INF = ~0LL;
const int prime[16] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};

struct child{
    char name[11];
    int val;
    inline void read(){scanf("%s %d\n", name, &val);}
}arr[N];

LL maxNum, ansPos, n;

void dfs(int dep, LL tmp, int num){
    if (dep >= 16) return;
    if (num > maxNum){
        maxNum = num;
        ansPos = tmp;
    }
    if (num == maxNum && ansPos > tmp) ansPos = tmp;
    for (int i = 1; i < 63; i++){
        if (n / prime[dep] < tmp) break;
        dfs(dep+1, tmp *= prime[dep], num*(i+1));
    }
}

struct segmentTree
{
    #define lc (rt<<1)
    #define rc (rt<<1^1)
    #define lson l, m, rt<<1
    #define rson m+1, r, rt<<1^1
    int val[N], M;

    inline void build(int n){
        M = 1; while(M<n) M<<=1; M--;
        for (int leaf = 1+M; leaf <= n+M; leaf++) val[leaf] = 1;
        for (int leaf = n+1+M; leaf <= (M<<1^1); leaf++) val[leaf] = 0;
        for (int rt = M; rt >= 1; rt--) val[rt] = val[lc] + val[rc];
    }

    inline int update(int pos, int rt){
        val[rt]--;
        if (rt > M) return rt - M;
        if (val[lc] >= pos) return update(pos, lc);
        else return update(pos-val[lc], rc);
    }
} T;

int main(){
    //freopen("in.txt", "r", stdin);
    int &mod = T.val[1];
    for (LL k; ~scanf("%lld%lld\n", &n, &k);){
        for (int i = 1; i <= n; i++) arr[i].read();
        T.build(n);
        ansPos = INF;
        maxNum = 0;
        dfs(0, 1, 1);

        int pos = 0;
        for (int i = 1; i <= ansPos; i++){
            pos = T.update(k, 1);
            //printf("k = %lld, pos = %d, mod = %d\n", k, pos, mod);
            if (mod == 0) break;
            if (arr[pos].val>0) k = (k-1 + arr[pos].val) % mod;
            else k = ((k + arr[pos].val) % mod + mod) % mod;
            if (k == 0) k = mod;
        }
        printf("%s %lld\n", arr[pos].name, maxNum);
    }
    return 0;
}

區間修改

dota配圖好評!!!

區間修改,最後一下查詢總sum

因為這個查詢就一次,而且還就直接存在根節點,所以就直接輸出了

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 5e6 + 7;

struct segmentTree
{
    #define lc (rt<<1)
    #define rc (rt<<1^1)
    #define lson l, m, rt<<1
    #define rson m+1, r, rt<<1^1
    int M, sum[N], tag[N];
    // 這裡相對於常見的線段樹,多了一個M,
    // M的實際含義為非葉子節點的數量,
    // 原陣列索引為x,線上段樹陣列中的索引就是 M + x

    // 因此,build可以改為自底向上的build
    // n個實際有效的葉子節點,M+1-n個空值的葉子節點
    inline void build(int n){
        M = 1; while(M<n) M<<=1; M--;
        memset(tag, 0, sizeof(tag));
        // leaf nodes with values
        for (int leaf = 1+M; leaf <= n+M; leaf++){
            sum[leaf] = 1;
        }
        // leaf nodes which is null
        for (int leaf = n+1+M; leaf <= (M<<1^1); leaf++){
            sum[leaf] = 0;
        }
        // non-leaf nodes(include root)
        for (int rt = M; rt >= 1; rt--){
            sum[rt] = sum[lc] + sum[rc];
        }
    }

    inline void pushUp(int rt){
        sum[rt] = sum[lc] + sum[rc];
    }

    inline void pushDown(int rt, int len){
        if (!tag[rt]) return;
        tag[lc] = tag[rc] = tag[rt];
        sum[lc] = sum[rc] = tag[rt] * (len>>1);
        tag[rt] = 0;
    }

    inline void update(int L, int R, int x, int l, int r, int rt){
        //printf("update(%d, %d, %d, %d, %d, %d)\n", L, R, x, l, r, rt);
        if (L <= l && r <= R){
            tag[rt] = x;
            sum[rt] = (r-l+1) * x;
            return;
        }
        pushDown(rt, r-l+1);
        int m = (l+r) >> 1;
        if (L <= m) update(L, R, x, lson);
        if (m <  R) update(L, R, x, rson);
        pushUp(rt);
    }
} T;

int main(){
    //freopen("in.txt", "r", stdin);
    int _, n, q, l, r, x;
    scanf("%d", &_);
    for (int __ = 1; __ <= _; __++){
        scanf("%d%d", &n, &q);
        T.build(n);
        for (;q--;){
            scanf("%d%d%d", &l, &r, &x);
            T.update(l, r, x, 1, T.M+1, 1);
        }
        printf("Case %d: The total value of the hook is %d.\n", __, T.sum[1]);
    }
    return 0;
}
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL N = 5e5 + 7;

struct segmentTree
{
    #define lc (rt<<1)
    #define rc (rt<<1^1)
    #define lson l, m, rt<<1
    #define rson m+1, r, rt<<1^1
    LL M, sum[N], tag[N];
    // 這裡相對於常見的線段樹,多了一個M,
    // M的實際含義為非葉子節點的數量,
    // 原陣列索引為x,線上段樹陣列中的索引就是 M + x

    // 因此,build可以改為自底向上的build
    // n個實際有效的葉子節點,M+1-n個空值的葉子節點
    inline void build(LL n){
        M = 1; while(M<n) M<<=1; M--;
        memset(tag, 0, sizeof(tag));
        // leaf nodes with values
        for (LL leaf = M+1; leaf <= n+M; leaf++){
            scanf("%lld", &sum[leaf]);
        }
        // leaf nodes which is null
        for (LL leaf = n+1+M; leaf <= (M<<1^1); leaf++){
            sum[leaf] = 0;
        }
        // non-leaf nodes(include root)
        for (LL rt = M; rt >= 1; rt--){
            sum[rt] = sum[lc] + sum[rc];
        }
    }

    inline void pushUp(LL rt){
        sum[rt] = sum[lc] + sum[rc];
    }

    inline void pushDown(LL rt, LL len){
        if (tag[rt] == 0) return;
        tag[lc] += tag[rt];
        tag[rc] += tag[rt];
        sum[lc] += tag[rt] * (len>>1);
        sum[rc] += tag[rt] * (len>>1);
        tag[rt] = 0;
    }

    inline void update(LL L, LL R, LL x, LL l, LL r, LL rt){
        //prLLf("update(%d, %d, %d, %d, %d, %d)\n", L, R, x, l, r, rt);
        if (L <= l && r <= R){
            tag[rt] += x;
            sum[rt] += (r-l+1) * x;
            return;
        }
        pushDown(rt, r-l+1);
        LL m = (l + r) >> 1;
        if (L <= m) update(L, R, x, lson);
        if (m <  R) update(L, R, x, rson);
        pushUp(rt);
    }

    LL query(LL L, LL R, LL l, LL r, LL rt){
        if (L <= l && r <= R) return sum[rt];
        pushDown(rt, r-l+1);
        LL m = (l + r) >> 1;
        LL ans = 0;
        if (L <= m) ans += query(L, R, lson);
        if (m <  R) ans += query(L, R, rson);
        return ans;
    }
} T;

int main(){
    //freopen("in.txt", "r", stdin);
    LL n, q, l, r, x;
    char ch;
    for (;~scanf("%lld%lld", &n, &q);){
        T.build(n);
        for (;q--;){
            getchar();
            scanf("%c%lld%lld", &ch, &l, &r);
            if (ch == 'Q'){
                printf("%lld\n", T.query(l, r, 1, T.M+1, 1));
            } else {
                scanf("%lld", &x);
                T.update(l, r, x, 1, T.M+1, 1);
            }
        } 
    }
    return 0;
}

by cww97

這裡寫圖片描述

因為這個圖所以,不能當做左閉右開的線段樹來做

and,卡了兩個小時是因為

這個傻逼錯誤

//for (int i = 1; i <= A; i++) {
//  x[a[i]] = i;//啊啊啊啊啊啊啊啊啊啊啊啊啊啊
    //printf("x[%d] = %d\n", a[i], i);
//}

T.build(A);
for (int i = 1; i <= n; i++){
    int L = lower_bound(a+1, a+A+1, l[i]) - a;//x[l[i]]
    int R = lower_bound(a+1, a+A+1, r[i]) - a;//x[r[i]]
    //printf("(%d, %d)\n", L, R);
    T.update(L, R, i, 1, T.M+1,1);
}

媽的離散化忘了用lower_bound,還開陣列存

發現錯誤前懷疑資料

發現錯誤後被自己蠢哭

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 2e5 + 7;

int l[N], r[N], n;
int a[N], A, x[N];
bool vis[N];
int ans;

struct segmentTree
{
    #define lc (rt<<1)
    #define rc (rt<<1^1)
    #define lson l, m, rt<<1
    #define rson m+1, r, rt<<1^1
    int M, col[N];

    inline void build(int n){
        M = 1; while(M<n)M<<=1; M--;
        memset(col, 0, sizeof(col));
    }

    inline void pushDown(int rt){
        if (col[rt] == 0) return;
        col[lc] = col[rc] = col[rt];
        col[rt] = 0;
    }

    inline void update(int L, int R, int x, int l, int r, int rt){
        if (L <= l && r <= R){
            col[rt] = x;
            return;
        }
        pushDown(rt);
        int m = (l + r) >> 1;
        if (L <= m) update(L, R, x, lson);
        if (m <  R) update(L, R, x, rson);
    }

    inline int query(int rt){
        if (col[rt] > 0) {
            if (vis[col[rt]]) return 0;
            vis[col[rt]] = 1;
            return 1;
        }
        if (rt > M) return 0;
        int ans = 0;
        ans += query(lc);
        ans += query(rc);
        return ans;
    }
} T;

int main(){
    //freopen("in.txt", "r", stdin);
    int _;
    scanf("%d", &_);
    for (;_--;){
        scanf("%d", &n);
        A = 0;
        for (int i = 1; i <= n; i++){
            scanf("%d%d", &l[i], &r[i]);
            a[++A] = l[i];
            a[++A] = r[i];
        }
        sort(a + 1, a + A+1);
        A = unique(a + 1, a + A+1) - (a + 1);
        for (int i = A; i > 1; i--){
            if (a[i-1] + 1 < a[i]) a[++A] = a[i-1] + 1;
        }
        sort(a + 1, a + A+1);

        T.build(A);
        for (int i = 1; i <= n; i++){
            int L = lower_bound(a+1, a+A+1, l[i]) - a;
            int R = lower_bound(a+1, a+A+1, r[i]) - a;
            T.update(L, R, i, 1, T.M+1,1);
        }
        ans = 0;
        memset(vis, 0, sizeof(vis));
        printf("%d\n", T.query(1));
    }
    return 0;
}

這裡寫圖片描述

1.關於集合運算的推導規約,知道集合是什麼東西就一定會推導!

U:把區間[l,r]覆蓋成1
I:把[-∞,l)(r,∞]覆蓋成0    
D:把區間[l,r]覆蓋成0
C:把[-∞,l)(r,∞]覆蓋成0 , 且[l,r]區間0/1互換
S:[l,r]區間0/1互換

2.倍化區間處理開閉區間的問題。因為普通的線段樹實際處理的並非真正的區間,而是一系列點,相當於處理一個向量。這個問題需要處理的是真正的區間,所以應該有一個主導思想就是,把區間點化!不知哪位大牛搞了一個倍增區間出來,實在佩服!對於待處理區間a,b,對其邊界均乘2。若區間左開則對左界值+1,若區間右開,則對右界-1!

如:[2,3]會倍增為[4,6],[2,3)會倍增為[4,5],(2,3]會倍增為[5,6],(2,3)將倍增為[5,5],我們這時可以看到,對於普通線段樹無法處理的線段如(x,x+1)將被點化為[2*x+1,2*x+1]!這個問題得到比較完美的解決

最後把查找出來的區間逆向倍增操作一下,就可以得到實際的區間以及起開閉情況!

程式碼中還將用到延遲更新,向子節點更新操作時,這個具體糾結在互換上面,不過仔細想想還是容易理解的,下面程式碼會有註解!

本題包含區間01賦值和區間01取反

一開始準備tree當做值,lazy當做是否取反的標記

wa了,lj跟我抱怨:你就不能老老實實寫個雙標記線段樹嗎

好的,雙標記,反正最後我query到所有的葉子節點,兩個標記亦或一下就是值,狗拿耗子,貓下崗了,tree後來,看起來是值,其實是另一個標記,不需要pushUp反正沒有區間查詢

本題略考驗程式碼能力,很容易WA哭(比如我自己(劃掉)),百度到的大部分題解都是學的kuangbin的寫法,一個update,update裡面分5個大if,我的是在main裡面if,線段樹就兩個功能,區間賦值和取反,剩下的交給int main來組織

銘記一點,老老實實寫雙標記,別搞騷操作

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 131072 + 7;
int ans[N];

struct segTree{
    #define lc rt<<1
    #define rc rt<<1^1
    #define lson l, m, rt<<1
    #define rson m+1, r, rt<<1^1
    int tree[N<<1], lazy[N<<1];

    inline void build(){
        memset(lazy, 0, sizeof(lazy));
        memset(tree, 0, sizeof(tree));
    }

    inline void pushDown(int rt){
        if (tree[rt] != -1){ // -1: mixture
            tree[lc] = tree[rc] = tree[rt];
            lazy[lc] = lazy[rc] = 0;
        }
        if (lazy[rt]){
            if (tree[lc] != -1) tree[lc] ^= 1;
            else lazy[lc] ^= 1;
            if (tree[rc] != -1) tree[rc] ^= 1;
            else lazy[rc] ^= 1;
            lazy[rt] = 0;
        }
        tree[rt] = -1;
    }

    void setval(int L, int R, int val, int l, int r, int rt){
        if (L <= l && r <= R) {
            tree[rt] = val;
            lazy[rt] = 0;
            return;
        }
        pushDown(rt);
        int m = (l + r) >> 1;
        if (L <= m) setval(L, R, val, lson);
        if (m <  R) setval(L, R, val, rson);
    }

    void invert(int L, int R, int l, int r, int rt){
        if (L <= l && r <= R){
            if (tree[rt] != -1) tree[rt] ^= 1;
            else lazy[rt] ^= 1;
            return;
        }
        pushDown(rt);
        int m = (l + r) >> 1;
        if (L <= m) invert(L, R, lson);
        if (m <  R) invert(L, R, rson);
    }

    void query(int l, int r, int rt){
        if (l == r){ // leaf
            ans[l] = tree[rt] ^ lazy[rt];
            return;
        }
        pushDown(rt);
        int m = (l + r) >> 1;
        query(lson);
        query(rson);
    }
} T;

int main(){
    //freopen("in.txt", "r", stdin);
    char op, lseg, rseg;
    int l, r, n = 131072;
    T.build();
    for (;~scanf("%c %c%d,%d%c\n", &op, &lseg, &l, &r, &rseg);){
        l <<= 1, r <<= 1;
        if (lseg == '(') l++;
        if (rseg == ')') r--;
        //printf("--------> %c [%d, %d]\n", op, l, r);
        if (l > r){
            if (op == 'I' || op == 'C'){
                T.setval(0, n, 0, 0, n, 1);
            }
        } else if (op == 'U'){ // S = S | T
            T.setval(l, r, 1, 0, n, 1);
        } else if (op == 'I'){ // S = S & T
            if (l > 0) T.setval(0, l-1, 0, 0, n, 1);
            if (r < n) T.setval(r+1, n, 0, 0, n, 1);
        } else if (op == 'D'){ // S = S - T
            T.setval(l, r, 0, 0, n, 1);
        } else if (op == 'C'){ // S = T - S
            T.invert(l, r, 0, n, 1);
            if (l > 0) T.setval(0, l-1, 0, 0, n, 1);
            if (r < n) T.setval(r+1, n, 0, 0, n, 1);
        } else { // op == 'S': S = S^T = (S-T)|(T-S)
            T.invert(l, r, 0, n, 1);
        }
    }
    T.query(0, n, 1);
    bool haveAns = 0, haveOne = 0;
    for (int i = 0; i <= n; i++){
        if (!haveOne && ans[i]){
            if (haveAns) putchar(' ');
            haveAns = haveOne = 1;