• 【UOJ#228】基础数据结构练习题 线段树


    #228. 基础数据结构练习题

    题目链接:http://uoj.ac/problem/228

    Solution

    这题由于有区间+操作,所以和花神还是不一样的。 花神那道题,我们可以考虑每个数最多开根几次就会成1,而这个必须利用开根的性质

    我们维护区间最大、最小、和。区间加操作可以直接做。

    区间开方操作需要特殊考虑。

    首先对于一个区间,如果这个区间的所有数取$x=left lfloor sqrt{x} ight floor$值一样,那么就可以直接区间覆盖。

    分析上述过程,一个区间可以直接覆盖,当这个区间的差值满足一个特定的范围。 而每次开方这个差值就会减少,可以证明这样开方$lg^{2}$次就会全部为1

    所以剩下的我们就可递归下去。

    这样的话,区间+操作,就相当于重置了这个差值,所以复杂度还是科学的。

    但是有一种情况出现问题。

    上述是每次开方后,差值减小,但是有开方后差值不变的情况。  例如 3 4 3 4 3 4 3 4

    即$a$,$b$当$b$为完全平方数,$a=b-1$时。这样开方完差值还是1,然后区间+2就又变回来了。 这样上述就卡成了暴力。

    那么我们把这种情况特殊考虑。 这样可以转化为一个区间-的操作。剩下的暴力递归,这样就可以了。

    时间复杂度是$O(NlogNlg^2{N})$

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define LL long long
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    #define MAXN 100010
    int N,M,a[MAXN];
    namespace SegmentTree
    {
        struct SegmentTreeNode{int l,r,cov; LL tag,sum,maxx,minx;}tree[MAXN<<2];
        #define ls now<<1
        #define rs now<<1|1
        inline void Update(int now)
        {
            tree[now].sum=tree[ls].sum+tree[rs].sum;
            tree[now].maxx=max(tree[ls].maxx,tree[rs].maxx);
            tree[now].minx=min(tree[ls].minx,tree[rs].minx);
        }
        inline void cover(int now,int D)
        {
            tree[now].cov=D; tree[now].tag=0;
            tree[now].minx=tree[now].maxx=D;
            tree[now].sum=D*(tree[now].r-tree[now].l+1);
        }
        inline void modify(int now,LL D)
        {
            tree[now].tag+=D;
            tree[now].minx+=D; tree[now].maxx+=D; tree[now].sum+=(tree[now].r-tree[now].l+1)*D;
        }
        inline void PushDown(int now)
        {
            if (tree[now].l==tree[now].r) return;
            if (tree[now].cov!=-1)
                cover(ls,tree[now].cov),cover(rs,tree[now].cov),tree[now].cov=-1;        
            if (tree[now].tag!=0)
                modify(ls,tree[now].tag),modify(rs,tree[now].tag),tree[now].tag=0;
        }
        inline void BuildTree(int now,int l,int r)
        {
            tree[now].l=l; tree[now].r=r; tree[now].cov=-1;
            if (l==r) {tree[now].sum=tree[now].maxx=tree[now].minx=a[l]; return;} 
            int mid=(l+r)>>1;
            BuildTree(ls,l,mid); BuildTree(rs,mid+1,r);
            Update(now);
        }
        inline void Modify(int now,int L,int R,int D)
        {
            int l=tree[now].l,r=tree[now].r;
            PushDown(now);
            if (L<=l && R>=r) {modify(now,D); return;}
            int mid=(l+r)>>1;
            if (L<=mid) Modify(ls,L,R,D);
            if (R>mid) Modify(rs,L,R,D);
            Update(now);
        }
        inline void Change(int now,int L,int R)
        {
            int l=tree[now].l,r=tree[now].r;
            PushDown(now);
            if (L<=l && R>=r)
                {
                    if ((int)sqrt(tree[now].maxx)==(int)sqrt(tree[now].minx)) 
                        {cover(now,(int)sqrt(tree[now].maxx)); return;}
                    if (tree[now].maxx==tree[now].minx+1) 
                        {modify(now,(int)sqrt(tree[now].minx)-tree[now].minx); return;}
                    if (l!=r) Change(ls,L,R),Change(rs,L,R);
                    Update(now);
                    return;
                }
            int mid=(l+r)>>1;
            if (L<=mid) Change(ls,L,R);
            if (R>mid) Change(rs,L,R);
            Update(now);
        }
        inline LL Query(int now,int L,int R)
        {
            int l=tree[now].l,r=tree[now].r;
            PushDown(now);
            if (L<=l && R>=r) return tree[now].sum;
            int mid=(l+r)>>1; LL re=0;
            if (L<=mid) re+=Query(ls,L,R);
            if (R>mid) re+=Query(rs,L,R);
            return re;
        }
    }
    int main()
    {
        N=read(),M=read();
        for (int i=1; i<=N; i++) a[i]=read();
        SegmentTree::BuildTree(1,1,N);
        while (M--)
            {
                int opt=read(),l=read(),r=read(),D;
                switch (opt)
                    {
                        case 1: D=read(),SegmentTree::Modify(1,l,r,D); break;
                        case 2: SegmentTree::Change(1,l,r); break;
                        case 3: printf("%lld
    ",SegmentTree::Query(1,l,r)); break;
                    }
    //            for (int i=1; i<=N; i++) printf("%d  ",SegmentTree::Query(1,i,i)); puts("=================");
            }
        return 0;
    }
  • 相关阅读:
    2019-2020-2 20174313张博《网络对抗技术》Exp5 信息搜集与漏洞扫描
    2019-2020-2 20174313张博《网络对抗技术》Exp4 恶意代码分析
    2019-2020-2 20174313张博《网络对抗技术》Exp3-免杀原理与实践
    2019-2020-2 20174313张博《网络对抗技术》Exp2-后门原理与实践
    2019-2020-2 20174313张博 《网络对抗技术》Exp1 PC平台逆向破解
    Exp9 Web安全基础
    实验八 Web基础
    实验七-网络欺诈防范
    MSF基础应用
    信息搜集与漏洞扫描
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5914062.html
Copyright © 2020-2023  润新知