luogu 4145 花神游历各国 线段树/树状数组+并查集

此题一看便是RMQ问题,但是由于开平方的特殊操作,tag操作失效

此时发现特性:sqrt最多执行6此便使值到达1/0,此时可以剪枝不进行该操作,利用并查集到达特性找根,根代表还可以进行操作的点,再利用树状数组简单的操作便可以AC

#include<bits/stdc++.h>
#define rep(i,x,y) for(register ll i=x;i<=y;i++)
#define ll long long
using namespace std;
const ll N=100500;
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;}ll k,fa[N],n,m,a[N],c[N];
inline ll lowbit(ll x){return x&(-x);}
inline void add(ll x,ll d){while(x<=n){c[x]+=d;x+=lowbit(x);};}
inline ll query(ll x){ll ans=0;while(x){ans+=c[x];x-=lowbit(x);};return ans;}
inline ll find(ll x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int main(){
    freopen("3038.in","r",stdin);
    freopen("3038.out","w",stdout);
    n=read();rep(i,1,n) a[i]=read(),add(i,a[i]),fa[i]=i;fa[n+1]=n+1;
    m=read();rep(i,1,m){
        ll q=read(),l=read(),r=read();
        if(l>r) swap(l,r);
        if(q==1) printf("%lld\n",query(r)-query(l-1));
        else
            for(ll j=find(l);j<=r;j=find(j+1)){
                ll t=sqrt(a[j]);add(j,t-a[j]);a[j]=t;
                
                if(a[j]<=1) fa[j]=find(j+1);}
    }return 0;    
}

 

posted @ 2018-09-11 11:44  ASDIC减除  阅读(90)  评论(0编辑  收藏  举报