ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P5268 一个简单的询问(莫队+容斥)

2021-11-18 01:01:38  阅读:173  来源: 互联网

标签:r1 r2 get int 容斥 l2 l1 莫队 P5268


目录

Description

给你一个长度为 NNN 的序列 aia_iai,1iN1\leq i\leq N1≤i≤N,和 qqq 组询问,每组询问读入 l1,r1,l2,r2l_1,r_1,l_2,r_2l1,r1,l2,r2,需输出

x=0get(l1,r1,x)×get(l2,r2,x)\sum\limits_{x=0}^\infty \text{get}(l_1,r_1,x)\times \text{get}(l_2,r_2,x) x=0∑∞get(l1,r1,x)×get(l2,r2,x)

get(l,r,x) \text{get}(l,r,x)get(l,r,x) 表示计算区间 [l,r][l,r][l,r] 中,数字 xxx 出现了多少次。

State

\(n,m<=50000\)

\(1<=a[i]<=n\)

Input

5
1 1 1 1 1
2
1 2 3 4
1 1 4 4

Output

4
1

Solution

题目 \(r_1,l_2\) 的大小并不明确,需要另一种新颖的容斥方法

另 \([l,r]\) 为区间内 \(x\) 的个数,\(x\) 任意

之后 \([l1,r1]*[l2,r2]\) 可以转化为

\[[1,r1]*[1,r2]-[1,r1]*[1,l2-1]-[1,r2]*[1,l1-1]+[1,l1-1]*[1,l2-1] \]

每一个区间的左端点都为 \(1\),所以可以将一个区间分为 \(4\) 个不同的区间,而他们的左端点都为 \(1\);

也就是说对于每一个端点 \(l,r\) 对于 \(1\) 来说,都是右端点

\(hint:\) 区间大小是题目所给的 \(4\) 倍

Code

const int N = 5e4 * 4 + 5;
 
    int n, m;
    int a[N];
    struct Query
    {
        int l, r;
        int bel;
        int id, tag;
        bool operator<(Query o){
            return bel == o.bel ? r < o.r: l < o.l;
        }
        Query(int l = 0, int r = 0, int id = 0, int tag = 0, int bel = 0) : l(l), r(r), bel(bel), id(id), tag(tag){}
    }q[N];
    int block, pre[N], suf[N];
    int tot = 0;
    ll ans[N], now;

void add(int pos, int *on, int *nxt)
{
    int x = a[pos];
    now += nxt[x];
    on[x] ++;
}

void del(int pos, int *on, int *nxt)
{
    int x = a[pos];
    now -= nxt[x];
    on[x] --;
}

void mo()
{
    block = 3 * sqrt(n);
    for(int i = 1; i <= tot; i ++){
        if(q[i].l > q[i].r) swap(q[i].l, q[i].r);
        q[i].bel = q[i].l / block + 1;
    }
    sort(q + 1, q + 1 + tot);
}

signed main()
{
    while(~ sd(n)){
        rep(i, 1, n) sd(a[i]);
        sd(m);
        rep(i, 1, m){
            int x, y, nx, ny;
            sdd(x, y); sdd(nx, ny);
            q[++ tot] = Query(y, ny, i, 1);
            q[++ tot] = Query(x - 1, ny, i, -1);
            q[++ tot] = Query(nx - 1, y, i, -1);
            q[++ tot] = Query(x - 1, nx - 1, i, 1);
        }
        mo();
        int l = 0, r = 0;
        now = 0;
        for(int i = 1; i <= tot; i ++){
            while(l < q[i].l) add(++ l, pre, suf);
            while(l > q[i].l) del(l --, pre, suf);
            while(r < q[i].r) add(++ r, suf, pre);
            while(r > q[i].r) del(r --, suf, pre);
            ans[q[i].id] += now * q[i].tag;
        }
        rep(i, 1, m) pll(ans[i]);
    }
    return 0;
}

标签:r1,r2,get,int,容斥,l2,l1,莫队,P5268
来源: https://www.cnblogs.com/Segment-Tree/p/15570344.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有