花神游历各国 题解(小清新线段树/树状数组+并查集)

众所周知,这是一道小清新线段树

然而可以用树状数组水过去且跑得飞快

看到区间开方第一反应肯定是线段树懒标记区间修改之类的,但是这个东西似乎确凿不可维护

所以考虑暴力循环单点修改->T飞

于是我们关注一下开方本身的特殊性

我们知道,如果每次向下取整,一个数经过多次操作最终会变成1(或0)

事实上,大概经过 log(logx)次就会变成1

这是什么概念呢?经过博主测试,1e9只要经过五次开方取整就会变成1

那么接下来就能够利用1每次不必再操作优化复杂度

可以维护一个类似链表的结构,指向下一个>1的数,用并查集维护

并查集+树状数组这两种常数极小的结构组合起来简直快的飞起:

蒟蒻第一次上榜有点激动Orz

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

const int L=1<<20|1;
char buffer[L],*S,*T;
#define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)

typedef long long ll;
const int N=100005;
ll c[N];
int n,m,data[N],fa[N];
inline int read()
{
    int f=1,x=0;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;
}
int lb(int x){return x&-x;}
int findf(int x)
{
    if(x==fa[x])return x;
    fa[x]=findf(fa[x]);
    return fa[x];
}
void update(int p,int v)
{
    while(p<=n)c[p]+=v,p+=lb(p);
}
ll sum(int p)
{
    ll res=0;
    while(p)res+=c[p],p-=lb(p);
    return res;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)data[i]=read(),update(i,data[i]);
    m=read();
    for(int i=1;i<=n;i++)fa[i]=data[i]<=1?i+1:i;
    fa[n+1]=n+1;
    while(m--)
    {
        int op=read(),l=read(),r=read();
        if(op==1)printf("%lld\n",sum(r)-sum(l-1));
        else if(op==2)
            for(int i=l;i<=r;i=findf(i+1))
            {
                int sqt=(int)sqrt(data[i]);
                update(i,sqt-data[i]),data[i]=sqt;
                if(data[i]<=1)fa[i]=findf(i+1);
            }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Rorschach-XR/p/11008046.html

时间: 2024-10-05 05:01:46

花神游历各国 题解(小清新线段树/树状数组+并查集)的相关文章

BZOJ 3211 花神游历各国 (树状数组+并查集)

题解:首先,单点修改求区间和可以用树状数组实现,因为开平方很耗时间,所以在这个方面可以优化,我们知道,开平方开几次之后数字就会等于1 ,所以,用数组记录下一个应该开的数,每次直接跳到下一个不是1的数字进行开平方,至于这个数组,可以用并查集维护. #include <cstdio> #include <cmath> #include <iostream> using namespace std; typedef long long LL; LL c[100005]; in

Wikioi 2492 树状数组+并查集(单点更新区间查询)

刚开始做的时候用线段树做的,然后就跳进坑里了--因为要开方,所以区间的值都得全部变,然后想用lazy标记的,但是发现用不了,单点更新这个用不了,然后就不用了,就T了.然后实在不行了,看了别人的题解,原来是用树状数组+并查集的方法,唉--没想到啊! 因为开方之后多次那个数就会变成1了,所以是1的时候开方下去就没用了.树状数组更新的时候就把其更新的差更新即可,太机智了这题-- 昨天做了,然后出错找了好久都找不出来,原来是把s[i]写成c[i]了,然后答案一直错,晕-- #include <iostr

[BZOJ3211]花神游历各国&amp;&amp;[BZOJ3038] 上帝造题的七分钟2 树状数组+并查集

3211: 花神游历各国 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 4057  Solved: 1480[Submit][Status][Discuss] Description Input Output 每次x=1时,每行一个整数,表示这次旅行的开心度 Sample Input 4 1 100 5 5 5 1 1 2 2 1 2 1 1 2 2 2 3 1 1 4 Sample Output 101 11 11 HINT 对于100%的数据,

BZOJ 3211 花神游历各国 树状数组+并查集

题目大意:花神对每一个国家有一个喜爱程度,有的时候他会对连续的一段国家进行访问,求他的喜爱程度的和:有的时候他会对连续的一段国家产生厌恶,喜爱程度变成sqrt(x)下取整. 思路:乍一看好像是RMQ问题,用线段树就可以水过,但是开根号的标记怎么下传?这是一个严重的问题,所以我们要换一个思路. 注意到开根号有一个有趣的性质:sqrt(1) = 1,sqrt(0) = 0,而且所有的数字经过有限次的开根号运算都会变成1.这个性质就很好了.我们对每一个点暴力开根号,然后当这个店的点权变成1的时候就打一

【BZOJ3211】花神游历各国 树状数组 并查集 均摊分析

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44686727"); } 题解: 一个点开几次方就没啦.所以我们只需要修改不是0或者1的点就行了. 均摊基本O(n). 然后用并查集维护一个点右边第一个不是0的数. 手写读入果然高大上.卡rank神器. 顺便Orz一下wys大神. 代

POJ 2985 The k-th Largest Group(树状数组 并查集/查找第k大的数)

传送门 The k-th Largest Group Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8690   Accepted: 2847 Description Newman likes playing with cats. He possesses lots of cats in his home. Because the number of cats is really huge, Newman wants

CodeVS2492 上帝造题的七分钟2(树状数组+并查集)

传送门 树状数组模板题.注意优化,假设某个数的值已经是1了的话.那么我们以后就不用对他进行操作了,这个能够用并查集实现. 这道题还有个坑的地方,给出查询区间端点的a,b,有可能a>b. #include<cstdio> #include<cmath> #include<cctype> #include<iostream> using namespace std; inline void GET(int &t){ char c; t=0; do{

BZOJ 3038 上帝造题的七分钟2 树状数组+并查集

题目大意:一个序列,有两种操作,1.将一段数中的每一个数开根号.2.查询一段数的和. 思路:和3211是一个题,有兴趣的可以看看我的那篇博客. CODE: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 using namespace std; int cnt,asks

BZOJ 3211 花神游历各国 线段树题解

BZOJ 3211 花神游历各国 线段树题解 3211: 花神游历各国 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 2551  Solved: 946[Submit][Status][Discuss] Description Input Output 每次x=1时,每行一个整数,表示这次旅行的开心度 Sample Input 4 1 100 5 5 5 1 1 2 2 1 2 1 1 2 2 2 3 1 1 4 Sample Output 101