花神游历各国 题解(小清新线段树/树状数组+并查集)
Posted rorschach-xr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了花神游历各国 题解(小清新线段树/树状数组+并查集)相关的知识,希望对你有一定的参考价值。
众所周知,这是一道小清新线段树
然而可以用树状数组水过去且跑得飞快
看到区间开方第一反应肯定是线段树懒标记区间修改之类的,但是这个东西似乎确凿不可维护
所以考虑暴力循环单点修改->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;
以上是关于花神游历各国 题解(小清新线段树/树状数组+并查集)的主要内容,如果未能解决你的问题,请参考以下文章