上帝造题的七分钟/花神游历各国 树状数组+并查集

一,前言:

众所周知,有极其高级的数据结构,线段树,但是本人不会qwq
(会用线段树解此题的神犇请移步。本人只是个蒟蒻,第一次写题解,如有不对,请谅解。)

二,解法:

因此,我想到了一个特别的解法树状数组。~~好像这章标题是线段树~~
可是,如果进行普通的解法,时间复杂度是相当高,因此,我想到了**并查集**。

通过观察可以得到,数据范围是10^9,经过几次开方就能四舍五入为`1`。
所以我们要用并查集维护
如果当前的数不等于1,直接把他的祖先变成他自己即f[i]=i 如果当前数等于1,也直接把f[i]变成下一个不等于1的数的位置即 f[i]=j,i<j<n,a[j]!=1 

然后只用按题意,查找祖先是自己的数就可以。

最后才用树状数组维护   为什么并查集有这么多行(恼)

三,愉快的代码部分

#include<bits/stdc++.h>
#define maxn 100100
#define ll long long
using namespace std;
ll c[maxn*4],a[maxn];int fa[maxn],m,n,q,l,r,t;
int find(int x)
{
———删除部分———
}
void add(int x,ll y)
{
    for (;x<=n;x+=x&-x)
    {
        c[x]+=y;//读入 
    }
}
ll ask(int x)
{
    ll r=0;
    for (;x;x-=x&-x)
    {
        r+=c[x];//输出 
    }
    return r;
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        add(i,a[i]);
        fa[i]=i;//并查集 
    }
    scanf("%d",&m);
————删除部分————
    while(m--)
    {
        scanf("%d%d%d",&q,&l,&r);
        if (q==1)
        { 
            printf("%lld\n",ask(r)-ask(l-1));
        }
        else
        { 
            for (int i = l; i <= r;) 
            {  
                int t = (int)sqrt(a[i]);   
                add(i, a[i]-t);  
                a[i] = t; 
                fa[i] = (a[i] <= 1) ? i + 1 : i;  
                int new_i = (find(i) == i) ? i + 1 : fa[i];//更新 
                i = new_i;  
            }
        }
    }
}

本人删除了一部分代码,防止抄袭。
题解借鉴

6.29特增加一组错误和删除一行代码,不会标出

by:aqzjklo
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值