[BZOJ3211]花神游历各国-树状数组-并查集

来源:互联网 发布:淘宝如何使用分期付款 编辑:程序博客网 时间:2024/06/04 07:30

花神游历各国

Description

pic1

Input

pic2

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


这题好风骚的操作……


思路:
考虑到sqrt貌似没有什么办法维护,咱选择树状数组。
修改暴力就好,求和上树状数组。

然而修改暴力显然会出事。
但可以注意到,一个1e9以内的数sqrt不超过6次sqrt后就会变成1。
那么维护一个并查集,如果一个数为0或1,就把它合并到它右边的节点上。
然后在修改时就可以用并查集快速忽略所有操作后无变化的数了。

还有这种操作???

#include<iostream>#include<cmath>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>using namespace std;typedef long long ll;inline ll read(){    ll x=0;char ch=getchar();    while(ch<'0' || '9'<ch)ch=getchar();    while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();    return x;}inline bool chkmax(ll &a,ll b){if(a<b){a=b;return 1;}return 0;}inline int lolbit(int x){return x&(-x);}const int N=100009;ll n,m,bit[N],fa[N],a[N];inline void modify(int pos,ll val){    while(pos<=n)    {        bit[pos]+=val;        pos+=lolbit(pos);    }}inline ll query(int pos){    ll ret=0;    while(pos)    {        ret+=bit[pos];        pos-=lolbit(pos);    }    return ret;}inline int find(int x){    if(!fa[x] || fa[x]==x)return x;    return fa[x]=find(fa[x]);}int main(){    n=read();    for(int i=1,v;i<=n;i++)    {        modify(i,a[i]=read());        if(a[i]<=1)            fa[i]=i+1;    }    m=read();    for(int i=1,x,l,r;i<=m;i++)    {        x=read();        l=read();        r=read();        if(x==1)            printf("%lld\n",query(r)-query(l-1));        else        {            for(int j=l;j<=r;j=find(j+1))            {                ll tmp=sqrt(a[j]);                modify(j,tmp-a[j]);                a[j]=tmp;                if(tmp<=1)                    fa[j]=find(j+1);            }        }    }    return 0;}