線段樹開新坑: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;