Can you answer these queries? (线段树

题目

题意:

  初始给你n个数,通过m个操作,  操作0是使区间范围内的每一个a[i]都变成 根号a[i] ,操作1是查询区间范围内数字的和。

思路:

  如果一个节点sum[rt]是1的话,根号1还是1,重复遍历这个节点会大大增加计算次数。n和区间左右端点的范围都 <=1e5,所以一个节点最多遍历不超过10次。

  如果这个节点sum[rt]是1,那么标记这个节点vis[rt]=1,说明这个节点以后不用往下遍历了。如果一个节点的左右子节点vis[rt<<1]=1, vis[rt<<1|1]==1,那么vis[rt]=1。注意longlong 以及输入要多空一行。

#include<iostream>
#include<cstdio>
#include <cctype>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<cmath>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<map>
using namespace std;
#define ll long long
#define mem(a,x) memset(a,x,sizeof(a))
#define se second
#define fi first
const ll mod=1e9+7;
const int INF= 0x3f3f3f3f;
const int N=1e5+5;

ll add[N<<2],sum[N<<2];
ll a[N<<1];
int vis[N<<2];
 
/*
struct node
{
    int v,p;
}b[N<<2];

bool cmp(node x,node y)
{
    return x.v<y.v;
}*/

void push_up(int rt)
{
    sum[rt] = sum[rt<<1] + sum[rt<<1|1] ;
    vis[rt] = vis[rt<<1] & vis[rt<<1|1] ; //左右子节点的vis都是1 父节点才是1 
}
/*
void push_down(int rt,int ln ,int rn)
{
    if(add[rt])
    {
        add[rt<<1]=add[rt<<1|1]=add[rt];
        sum[rt<<1]=add[rt]*ln;
        sum[rt<<1|1]=add[rt]*rn;
        add[rt]=0;
    }
}*/
void Built(int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]=a[l];
        if(sum[rt]<=1) vis[rt]=1;
        return;
    }
    int m=l+r>>1;
    Built(l,m,rt<<1);
    Built(m+1,r,rt<<1|1);
    push_up(rt);
}

void update(int x,int y,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]= 1LL*sqrt(sum[rt]*1.0);
        if( sum[rt]<=1 ) vis[rt]=1;
        return;
    }
    int m=l+r>>1;
    //push_down(rt,m-l+1,r-m);
    if(x<=m && !vis[rt<<1]) update(x,y,l,m,rt<<1);
    if(m<y && !vis[rt<<1|1]) update(x,y,m+1,r,rt<<1|1);
    push_up(rt);
}

ll Query(int x,int y, int l,int r,int rt)
{
    if(x<=l && r<=y)
    {
        return sum[rt];
    }
    int m=l+r>>1;
    //push_down(rt,m-l+1,r-m);
    ll ans=0;
    if(x<=m) ans+=Query(x,y,l,m,rt<<1);
    if(m<y) ans+=Query(x,y,m+1,r,rt<<1|1);
    return ans;
}
int main()
{
    int x,y,c=0,n,m,q;
       while(~scanf("%d",&n) )
       {
           /*for(int i=1;i<=n;i++) scanf("%d",&b[i].v),b[i].p=i;
           sort(b+1,b+1+n,cmp);
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            if(b[i].v != b[i-1].v)
                cnt++;
               a[b[i].p]=cnt;
           }//离散化完毕  */
           for(int i=1;i<=n;i++)  scanf("%lld",&a[i]);
        mem(vis,0);
        mem(sum,0);
           Built(1,n,1);
           scanf("%d",&m);
           printf("Case #%d:\n",++c);
        while(m--)
        {
            scanf("%d%d%d",&q,&x,&y);
            if(x>y) swap(x,y);
            if(q==0)
                update(x,y,1,n,1);
            else
                printf("%lld\n",Query(x,y,1,n,1) );
        }
        cout<<endl;
    }
   
}

猜你喜欢

转载自www.cnblogs.com/thunder-110/p/10308275.html