bzoj3211花神游历各国

这篇博客主要介绍了如何应用树状数组和并查集解决bzoj3211(花神游历各国)问题。博主通过解析题目和给出的样例输入输出,探讨了线段树、暴力修改以及树状数组加并查集的解题思路,并解释了关键步骤,帮助读者理解解题过程中的逻辑和正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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%的数据, n ≤ 100000,m≤200000 ,data[i]非负且小于10^9

Source

SPOJ2713 gss4 数据已加强

看了好几道并查集的题都不会都说是和这道题一模一样
那么我们来看看这道题把。
首先可以用线段树暴力做复杂度大概多个log
线段树做就是暴力做法吧
我们来学习一下树状数组加并查集的更暴力的做法吧
思路是暴力修改l到r然后用并查集跳过那些已经不能继续开方的数
大概基本很多人的修改都是下面的这一句话

for(int j=l;j<=r;add(j,(t=(int)sqrt(a[j]))-a[j]),a[j]=t,
        f[j]=(a[j]<=1)?j+1:j,j=(find(j)==j?j+1:f[j]));

!这种东西我能看懂么
不存在的
不过好像第一行就是暴力修改的意思没啥可想的
如果j已经被削到1以下(开方没变化),那么原来连向j的那些应该指向j+1了,否则还指向j
第二句表示如果j还指向自己那么就一位一位走,否则直接从父亲转移。
对于正确性我觉得随便手玩一下就懂了
那么我们学会了新知识!!!
虽然只是能看懂自己根本写不出来

#include<cstdio>
#include<cstring>
#include<utility>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdlib>
#include<ctime>
using namespace std;
inline int read()
{
    char ch='*';
    int f=1;
    while(!isdigit(ch=getchar())) if(ch=='-') f=-1;
    int num=ch-'0';
    while(isdigit(ch=getchar())) num=num*10+ch-'0';
    return num*f;
}
typedef long long ll;
const int maxn = 100005;
ll c[maxn];
int a[maxn],f[maxn],n,m,op,l,r,t;
int find(int x){return x==f[x]? x:f[x]=find(f[x]);}
inline void add(int x ,int num) {while(x<=n) c[x]+=num,x+=x&-x;}
inline ll sum(int x){ll s = 0;while(x) s+=c[x],x-=x&-x;return s;}
int main()
{
    n=read();
    for(register int i=1;i<=n;i++) f[i]=i,a[i]=read(),add(i,a[i]);
    m=read();f[n+1]=n+1;
    for(register int i=1;i<=m;i++)
    {
        op=read();l=read();r=read();
        if(op==1){
            printf("%lld\n",(sum(r)-sum(l-1)));
        }
         else for(int j=l;j<=r;add(j,(t=(int)sqrt(a[j]))-a[j]),a[j]=t,
        f[j]=(a[j]<=1)?j+1:j,j=(find(j)==j?j+1:f[j]));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值