码迷,mamicode.com
首页 > 其他好文 > 详细

January 24th 模拟赛A T3【NOI2014模拟】数列 Solution

时间:2018-02-04 12:42:59      阅读:185      评论:0      收藏:0      [点我收藏+]

标签:log   b2c   str   ems   code   暴力   string   ret   pac   

题目空降

Description

给定一个长度为\(n\)的正整数数列\(a_i\)
定义两个位置的\(f\)为两者位置差与数值差的和,即\(f_{x,y}=|x-y|+|a_x-a_y|\)
你需要写一个程序支持两种操作(\(k\)都是正整数):

  1. Modify x k:将第\(x\)个数的值修改为\(k\)
  2. Query x k:询问有几个\(i\)满足\(f_{x,i}\leq k\)

询问不仅要考虑当前数列,还要考虑任意历史版本,即统计任意位置上出现过的任意数值与当前的\(a_x\)\(f\leq k\)的对数。(某位置多次修改为同样的数值,按多次统计)

Input

\(1\)行两个整数\(n,q\)。分别表示数列长度和操作数。
\(2\)\(n\)个正整数,代表初始数列。
\(3\sim q+2\)行每行一个操作。

Output

对于每次询问操作,输出一个非负整数表示答案。

Analysis

原题是查询旋转\(45^\circ\)的正方形内的点数。
技术分享图片
我们将其旋转回来,即旋转\(45^\circ\)
技术分享图片
即化为一个三维偏序问题:

  1. 时间
  2. \(x+a_x\)
  3. \(x-a_x\)

经典的做法是CDQ分治。(用二维线段树/树状数组勿喷)(不会的请自行百度)
技术分享图片
对于一段已时间为序的区间,将左段的修改点,右段的查询点提出。
用左段的修改点更新右段的查询点的答案。
技术分享图片
对于这样的查询,(众所周知)暴力做法是不可取的。
我们考虑树状数组。
利用树状数组维护上下区间\((h_1,h_2)\)之间的点。
稍加思考,便知道这样是不可取的。
技术分享图片
技术分享图片
因为这样红色区域的点会被出入树状数组多次。
技术分享图片
所以我们考虑避免这样的问题。
一个可行的办法是将正方形左右界提取:\(l-1,r\)
按照横坐标排序。
技术分享图片
技术分享图片
利用容斥原理,求出点数。(蓝色部分\(-\)黄色部分)
至此,问题得解。

P.S.

瞎BB。
在重置树状数组时,有如下办法:

  1. memset(f,0,sizeof(f));
  2. 一个一个重新清

方法1 显然 更简单。

但是!!!

技术分享图片
对于一个\(SIZE=360000\)的数组,\(O\left(SIZE\times log_2N\right)\) 的复杂度显然是不可取的。
所以应取方法2。

Code

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

struct node
{
    int x, y, k, ans, pos;
    bool bj;
};

const int MaxAi = 360000, AbsValue = 180000;

int n, q;
node d[120005];
int final[60005];
node E[120005], Q[120005];
int Etot, Qtot;
int f[360005];

int Lowbit(int x)
{
    return x & (-x);
}

void Change(int cod, int value)
{
    while (cod <= MaxAi)
    {
        f[cod] += value;
        cod += Lowbit(cod);
    }
}

int Sum(int x)
{
    int rs = 0;

    while (x > 0)
    {
        rs += f[x];
        x -= Lowbit(x);
    }

    return rs;
}

int Query(int l, int r)
{
    return Sum(r) - Sum(l - 1);
}

bool cmp(node a, node b)
{
    return a.x < b.x;
}

bool Get()
{
    int c = 0;
    bool rtn;

    for (c = getchar(); (c == ' ') || (c == '\r') || (c == '\n'); c = getchar());

    rtn = c == 'Q';

    for (c = getchar(); (c != ' ') && (c != '\r') && (c != '\n'); c = getchar());

    return rtn;
}

void Dfs(int l, int r)
{
    if (l >= r)
        return;

    int mid = (l + r) / 2;
    Dfs(l, mid), Dfs(mid + 1, r);
    Etot = Qtot = 0;

    for (int i = l; i <= mid; i++)
        if (!d[i].bj)
        {
            E[++Etot] = d[i];
            E[Etot].pos = i;
        }

    for (int i = mid + 1; i <= r; i++)
        if (d[i].bj)
        {
            Q[++Qtot] = d[i];
            Q[Qtot].x -= Q[Qtot].k * 2 + 1;
            Q[Qtot].pos = i;
            Q[Qtot].bj = true;
            Q[++Qtot] = d[i];
            Q[Qtot].pos = i;
            Q[Qtot].bj = false;
        }

    sort(E + 1, E + Etot + 1, cmp);
    sort(Q + 1, Q + Qtot + 1, cmp);
    //memset(f, 0, sizeof(f)); 方法1

    for (int i = 1, j = 1; i <= Qtot; i++)
    {
        while ((j <= Etot) && (E[j].x <= Q[i].x))
            Change(E[j].y + AbsValue, 1), j++;

        if (Q[i].bj)
            d[Q[i].pos].ans -= Query(Q[i].y - Q[i].k * 2 + AbsValue, Q[i].y + AbsValue);
        else
            d[Q[i].pos].ans += Query(Q[i].y - Q[i].k * 2 + AbsValue, Q[i].y + AbsValue);
    }
    //方法2
    for (int i = 1, j = 1; i <= Qtot; i++)
    {
        while ((j <= Etot) && (E[j].x <= Q[i].x))
            Change(E[j].y + AbsValue, -1), j++;
    }
}

int main(int argc, char const *argv[])
{
    freopen("init.in", "r", stdin);
    scanf("%d%d", &n, &q);

    for (int i = 1; i <= n; i++)
    {
        int tmp;
        scanf("%d", &tmp);
        d[i].x = i + tmp;
        d[i].y = i - tmp;
        final[i] = i;
    }

    for (int i = 1; i <= q; i++)
    {
        d[n + i].bj = Get();

        if (!d[n + i].bj)
        {
            scanf("%d%d", &d[n + i].x, &d[n + i].y);
            final[d[n + i].x] = n + i;
            d[n + i].x += d[n + i].y;
            d[n + i].y = d[n + i].x - d[n + i].y * 2;
        }
        else
        {
            int tmp;
            scanf("%d%d", &tmp, &d[n + i].k);
            d[n + i].x = d[final[tmp]].x + d[n + i].k;
            d[n + i].y = d[final[tmp]].y + d[n + i].k;
        }
    }

    n += q;
    Dfs(1, n);

    for (int i = 1; i <= n; i++)
        if (d[i].bj)
            printf("%d\n", d[i].ans);

    return 0;
}

January 24th 模拟赛A T3【NOI2014模拟】数列 Solution

标签:log   b2c   str   ems   code   暴力   string   ret   pac   

原文地址:https://www.cnblogs.com/Ace-Killing/p/JAN24_A_T3.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!