Educational Codeforces Round 137 (Rated for Div. 2) F Intersection and Union(线段树或者c++set)

题意:

给你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} 3n1种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)... opn1 Sn结果求和。

tip1:

其实我们可以把每个数,看成一个二进制位。
那么问题就转换成了
统计 3 n − 1 3^{n-1} 3n1种op选择后的最终结果的二进制下有多少1。

我们可以单独考虑一位,来算贡献。

tip2:

  • 我们发现每个位置,只用考虑最后覆盖他的区间。

假如当前最后覆盖的区间为 i i i.
前面 i − 1 i-1 i1个元素进行 i − 2 i-2 i2此运算的结果只有两种 0 / 1 0/1 0/1

  • 那么对于 i i i以前的我们 3 i − 2 3^{i-2} 3i2
  • i i i以后的都是 o r ∣ x o r or | xor orxor ,不能出现 a n d and and,因为会破坏这次贡献。所以后面的贡献为 2 n − i 2^{n-i} 2ni
  • 对于位置 i i i的操作:
前i-1的结果第i个位置的op结果
0XOR,OR1
1OR,AND1

所以 这个点的贡献为 3 i − 2 × 2 n − i + 1 3^{i-2} \times 2^{n-i+1} 3i2×2ni+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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值