题意:
给你n个线段
S
i
=
[
l
i
,
r
i
]
S_i=[l_i,r_i]
Si=[li,ri]
定义
- ∣ S ∣ |S| ∣S∣为集合里的元素个数
- o p op op 为(集合交|集合并|集合异或)
统计
3
n
−
1
3^{n-1}
3n−1种op选择,对
∣
(
(
S
1
o
p
1
S
2
)
o
p
2
S
3
)
.
.
.
o
p
n
−
1
S
n
∣
|((S_1 \ op_1 \ S_2)\ op_2 \ S_3)... \ op_{n-1} \ S_n|
∣((S1 op1 S2) op2 S3)... opn−1 Sn∣结果求和。
tip1:
其实我们可以把每个数,看成一个二进制位。
那么问题就转换成了:
统计
3
n
−
1
3^{n-1}
3n−1种op选择后的最终结果的二进制下有多少1。
我们可以单独考虑一位,来算贡献。
tip2:
- 我们发现每个位置,只用考虑最后覆盖他的区间。
假如当前最后覆盖的区间为
i
i
i.
前面
i
−
1
i-1
i−1个元素进行
i
−
2
i-2
i−2此运算的结果只有两种
0
/
1
0/1
0/1
- 那么对于 i i i以前的我们 3 i − 2 3^{i-2} 3i−2
- i i i以后的都是 o r ∣ x o r or | xor or∣xor ,不能出现 a n d and and,因为会破坏这次贡献。所以后面的贡献为 2 n − i 2^{n-i} 2n−i
- 对于位置 i i i的操作:
前i-1的结果 | 第i个位置的op | 结果 |
---|---|---|
0 | XOR,OR | 1 |
1 | OR,AND | 1 |
所以 这个点的贡献为 3 i − 2 × 2 n − i + 1 3^{i-2} \times 2^{n-i+1} 3i−2×2n−i+1
tip3:
一个位置最后被覆盖的区间:
- 我们可以线段树维护一个位置最后被哪个区间覆盖, O ( ( 3 e 5 ) ∗ l o g ( 3 e 5 ) ) O((3e5)*log(3e5)) O((3e5)∗log(3e5))
- 也可以倒着跑一遍,用set维护, O ( ( 3 e 5 ) ∗ l o g 2 ( 3 e 5 ) ) O((3e5)*log^2(3e5)) O((3e5)∗log2(3e5))
What’s more
红名好多大佬都是跑矩阵。。。qwq
AC(JAVA)
package com.hgs.codeforces.contest.edu.contest137.f;
/**
* @author youtsuha
* @version 1.0
* Create by 2022/10/18 0:13
*/
import java.util.*;
import java.io.*;
public class Main {
static FastScanner cin;
static PrintWriter cout;
private static void init()throws IOException {
cin = new FastScanner(System.in);
cout = new PrintWriter(System.out);
}
private static void close(){
cout.close();
}
static class TreeNode{
int u, l, r, v, tag;
public TreeNode(int u, int l, int r) {
this.u = u;
this.l = l;
this.r = r;
}
public TreeNode() {
}
public int getU() {
return u;
}
public void setU(int u) {
this.u = u;
}
public int getL() {
return l;
}
public void setL(int l) {
this.l = l;
}
public int getR() {
return r;
}
public void setR(int r) {
this.r = r;
}
public int getV() {
return v;
}
public void setV(int v) {
this.v = v;
}
public int getTag() {
return tag;
}
public void setTag(int tag) {
this.tag = tag;
}
}
static TreeNode tr[] = new TreeNode[(int) (3e5+10)*4];
static void build(TreeNode[] tr, int u, int l, int r){
if(l == r) tr[u] = new TreeNode(u,l,r);
else {
tr[u] = new TreeNode(u,l,r);
int mid = l + r >> 1;
build(tr, u*2, l, mid);
build(tr, u*2+1,mid+1,r);
}
}
/*static void pushup(TreeNode[] tr, int u){
int ls = u*2;
int rs = u*2+1;
tr[u].v = tr[ls].v + tr[rs].v;
}*/
static void pushdown(TreeNode[] tr, int u){
if(tr[u].tag > 0){
int ls = u*2;
int rs = u*2+1;
tr[ls].v = tr[u].tag;
tr[rs].v = tr[u].tag;
tr[ls].tag = tr[rs].tag = tr[u].tag;
tr[u].tag = 0;
}
}
static void mody(TreeNode[] tr, int u, int l, int r, int v){
if(l <= tr[u].l && tr[u].r <= r){
tr[u].tag = v;
tr[u].v = v;
}else {
pushdown(tr,u);
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) mody(tr, u*2, l, r, v);
if(r > mid) mody(tr, u*2+1, l, r, v);
}
}
static int query(TreeNode[] tr, int u, int x){
if(tr[u].l == x && tr[u].r == x){
return tr[u].v;
}else {
pushdown(tr,u);
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid) return query(tr, u*2, x);
else return query(tr, u*2+1, x);
}
}
static long mod = 998244353;
static long qpow(long a, long k, long p){
long res = 1;
while(k > 1) {
if( (k&1) ==1 ) res = res*a%k;
a = a*a%k;
k>>=1;
}
return res;
}
private static void sol()throws IOException {
int n = cin.nextInt();
build(tr,1,0, (int) 3e5);
for(int i = 0; i < n; i ++ ) {
int l = cin.nextInt(), r = cin.nextInt();
mody(tr,1,l,r, i+1);
}
long b2[] = new long[(int) (3e5+10)];
long b3[] = new long[(int) (3e5+10)];
b2[0] = b3[0] = 1;
for(int i = 1; i <= 3e5; i ++ ) {
b2[i] = b2[i-1] * 2 %mod;
b3[i] = b3[i-1] * 3 %mod;
}
long ans = 0;
for(int i = 0; i <= 3e5; i ++ ) {
int cnt = query(tr,1,i);
// if(i>=1 && i <= 9) cout.println("pos[" + i +"]=" + cnt);
long res = 0;
if(cnt == 0) continue;
else if(cnt == 1) res = b2[n-1];
else res = b3[cnt- 2]*b2[n - cnt + 1]%mod;
ans = (res + ans)%mod;
}
cout.print(ans);
}
public static void main(String[] args) throws IOException {
init();
sol();
close();
}
}
class FastScanner {
BufferedReader br;
StringTokenizer st = new StringTokenizer("");
public FastScanner(InputStream s) {
br = new BufferedReader(new InputStreamReader(s));
}
public FastScanner(String s) throws FileNotFoundException {
br = new BufferedReader(new FileReader(new File(s)));
}
public String next() throws IOException {
while (!st.hasMoreTokens()){
try {
st = new StringTokenizer(br.readLine());
} catch (IOException e) { e.printStackTrace(); }
}
return st.nextToken();
}
public int nextInt() throws IOException {
return Integer.parseInt(next());
}
public long nextLong() throws IOException {
return Long.parseLong(next());
}
public double nextDouble() throws IOException {
return Double.parseDouble(next());
}
}
AC(c++)
#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
#include <unordered_map>
#include <set>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <cmath>
#include <cstring>
#define For(i,x,y) for(int i = (x); i <= (y); i ++ )
#define fori(i,x,y) for(int i = (x); i < (y); i ++ )
#define sz(a) (int)a.size()
#define ALL(a) a.begin(), a.end()
#define mst(x,a) memset(x,a,sizeof(x))
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define fi first
#define se second
#define db double
#define endl '\n'
#define debug(a) cout << #a << ": " << a << endl
using namespace std;
typedef long long LL;
typedef long long ll;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int inf = 0x3f3f3f3f;
const int mod = 998244353 ;
typedef pair<int,int>pa;
typedef pair<ll,ll>pai;
typedef pair<db,db> pdd;
const db eps = 1e-6;
const db pi = acos(-1.0);
template<typename T1, typename T2> void ckmin(T1 &a, T2 b) { if (a > b) a = b; }
template<typename T1, typename T2> void ckmax(T1 &a, T2 b) { if (a < b) a = b; }
int read() {
int x = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= ch == '-', ch = getchar();
while (isdigit(ch)) x = 10 * x + ch - '0', ch = getchar();
return f ? -x : x;
}
template<typename T> void print(T x) {
if (x < 0) putchar('-'), x = -x;
if (x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
template<typename T> void print(T x, char let) {
print(x), putchar(let);
}
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
const int maxn = 300000 + 6;
ll qpow(ll a, ll k, ll p){
ll res = 1;
while(k){
if(k&1) res = res*a%p;
a = a*a%p;
k>>=1;
}
return res;
}
int l[maxn], r[maxn];
int n;
ll b2[maxn];
ll b3[maxn];
int pos[maxn];
set<int> home;
int main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
fill(pos,pos+1+(int)3e5,-1);
cin >> n;
for(int i = 1; i <= n; i ++ ) {
cin>>l[i] >> r[i];
}
for(int i = 0; i <= (int)3e5 + 1; i ++ ) home.insert(i);
for(int i = n; i >= 1; i -- ) {
int L = l[i], R = r[i];
auto it = home.lower_bound(L);
while(*it <= R){
pos[*it] = i;
home.erase(it);
it = home.lower_bound(L);
}
}
//init
b2[0] = b3[0] = 1;
for(int i = 1; i < maxn; i ++ ){
b2[i] = b2[i-1]*2%mod;
b3[i] = b3[i-1]*3%mod;
}
ll ans = 0;
for(int i = 0; i <= (int)(3e5); i ++ ) {
if(pos[i] == -1) continue;
int ind = pos[i];
ll res = 0;
if(ind == 1) {
res = 1*b2[n-1];
}else {
//前面都是0 | 1 = 1, 0^1 = 1
//前面都是1 | 1 = 1, 1&1 = 1
res = b3[ind-2]*b2[n-ind + 1]%mod;
}
ans = (ans + res)%mod;
}
print(ans);
return 0;
}