• $noi.ac$ #51 array 题解


    (noi.ac) #51 array题解

    2020-2-13 xiaoh

    题意

    有一个长度为(n)的序列a((1leq nleq 5 imes 10^7)),初始情况下(a_i)的值为(i),接下来有(m)个操作((1leq mleq 5 imes 10^5)),每个操作可能为以下两个之一:
    (A):对于所有的(iin [1,n]),将(a_i)改为(p imes i+q) ((|p|leq 10^3,|q|leq 10^9));
    (B):将(a_x)改为(y) ((|y|leq 10^9)).
    要求在每一次操作结束后输出 (Sigma a).

    题解

    由于(n)达到(10^7)级别,因此不可能暴力维护整个(a)序列。注意到修改为区间赋值和单点修改,所以考虑用数据结构维护"单点修改"修改过的元素。这样一来(A)操作就是清空整个数据结构并重新赋初值,(B)操作就是在数据结构上添加元素/修改,并将其计入总的(sum)中。所以我们的数据结构要实现动态插入,查询某个值是否存在,以及清空,且每个操作必须在 (log)级别以内的时间内完成。不难想到平衡树可以完成上述操作(代码中平衡树的实现为fhq-Treap,即非旋Treap)。时间复杂度O(mlogn),其中查询和添加为 (log)级别的,清空(O(1))

    Code

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=500010;
    int tot=0;
    int rt=0;
    long long sum;
    long long add=0,mul=1;
    struct node{//fhq-Treap的代码部分注释就不赘述了,就是一个板子
        int l,r;
        int val,dat;
        long long val2;
        int sz;
    }f[MAXN];
    inline void pushup(int p)
    {
        f[p].sz=f[f[p].l].sz+f[f[p].r].sz+1;
    }
    inline int New(int val,long long val2)
    {
        tot++;
        f[tot].val=val,f[tot].val2=val2,f[tot].dat=rand();
        f[tot].sz=1;
        return tot;
    }
    void split(int p,int k,int &x,int &y)
    {
        if(!p)
        {
            x=y=0;
            return;
        }
        if(f[p].val<=k)
        {
            x=p;
            split(f[p].r,k,f[p].r,y);
        }
        else
        {
            y=p;
            split(f[p].l,k,x,f[p].l);
        }
        pushup(p);
    }
    int merge(int a,int b)
    {
        if(!a||!b) return a+b;
        if(f[a].dat<f[b].dat)
        {
            f[a].r=merge(f[a].r,b);
            pushup(a);
            return a;
        }
        else
        {
            f[b].l=merge(a,f[b].l);
            pushup(b);
            return b;
        }
    }
    inline bool find(int val)//查找值是否存在
    {
        int x,y,z;
        split(rt,val-1,x,y);
        split(y,val,y,z);
        bool ret=(y!=0);
        rt=merge(merge(x,y),z);
        return ret;
    }
    inline void insert(int p,long long q)
    {
        if(find(p))//若值存在则直接修改
        {
            int x,y,z;
            split(rt,p-1,x,y);
            split(y,p,y,z);
            sum-=f[y].val2;
            sum+=q;
            f[y].val2=q;
            rt=merge(merge(x,y),z);
        }
        else//否则插入这个值
        {
            int x,y;
            split(rt,p,x,y);
            sum-=(long long)p*mul+add;
            sum+=q;
            rt=merge(merge(x,New(p,q)),y);
        }
    }
    int n,m;
    int main()
    {
        scanf("%d%d",&n,&m);
        sum=(long long)n*(long long)(n+1)/(long long)2;
        for(register int i=1;i<=m;i++)
        {
            char op[10];
            scanf("%s",op);
            if(op[0]=='A')
            {
                long long p,q;
                scanf("%lld%lld",&p,&q);
                mul=p,add=q;
                sum=(long long)n*(long long)(n+1)/(long long)2;//修改总和
                sum=sum*p+q*(long long)n;
                rt=0;//清空fhq-Treap
            }
            else
            {
                int x;
                long long y;
                scanf("%d%lld",&x,&y);
                insert(x,y);//修改对应的值
            }
            printf("%lld
    ",sum);
        }
    }
    

    后记

    一开始读这道题读错了,把(A)操作硬生生读成了(a_i=p imes a_i+q),然后看了看数据差点自爆,这个八成要高精,还要写pushdown,又懒得写高精,就直接套了long double……后来发现题读错的时候我已经在调样例了(QAQ)没办法,只能流着泪狂删代码+修改,结果因为long double常数太大居然又爆了一次,最终把long double全部换成long long之后才过……真是个悲伤的故事。

  • 相关阅读:
    1405ST软件测试课的要求补充说明
    软测实验课安排和考试
    Asp.Net 4.0 FormAuthentication 原理
    微信支付-“申请退款”接口遇到curl出错,错误码:58
    前端资源构建-Grunt环境搭建
    微信服务号开发-获取用户位置信息
    微信支付开发-当前页面的URL未注册
    Using Redis to store php session
    nginx performance monitor
    thinkphp nginx php-fpm url rewrite 导致 404 错误
  • 原文地址:https://www.cnblogs.com/xiaoh105/p/12303164.html
Copyright © 2020-2023  润新知