现在的位置: 首页 > 综合 > 正文

hdu 4902 线段树

2014年10月03日 ⁄ 综合 ⁄ 共 2272字 ⁄ 字号 评论关闭

这道题是昨天多校联合比赛的1006题,我是用线段树(区间树)做的,这道题还可以用暴力做。

但是用线段树耗时1200ms,时间复杂度很低。而暴力至少得8000ms,

但是这道题提交了很多遍,但都是wrong ansers ,今天再重新交了一遍,之所以wrong 是因为杭电用%I64d 输入输出。而我用的是long long 

坑......................

附上代码:

   

    #include <stdio.h>
    #include <string.h>
    #include <cmath>
    #include <iostream>
    typedef long long ll;
    using namespace std;

    const  int  maxn=101000;
    struct node
    {
        int l,r,cover;  // 这里的cover的值要么为0 要么为1 ,当cover==1的时候表示这个区间所有的值都相等
        ll inc;         //这个值的意思用于1操作和2操作时的记录,这样就不必要每次操作到叶子节点,时间复杂度能下去;
    }data[maxn*8];

    ll a[maxn+1];
    ll GCD(ll a,ll b)   //最大公约数公式
    {
      if(!b)return a;
      return GCD(b,a%b);
    }

    void build(int l,int r,int k)  //建树的过程
    {
        int mid;
        data[k].l=l;
        data[k].r=r;
        data[k].inc=0;
        data[k].cover=0;
        if (l==r)
        {
          data[k].inc=a[l];
          data[k].cover=1;
          return ;
        }
        mid=(l+r)/2;
        build(l,mid,k*2);
        build(mid+1,r,k*2+1);
    }

    void change(int k,int l,int r,ll x) //1 操作。。。。
    {
        int mid;
        if (data[k].l==l&&data[k].r==r)  //找到这个区间后,把要更改的x值用inc记录,然后cover==1,表示这个区间内所有数都为x了
        {
            data[k].inc=x;
            data[k].cover=1;
            return ;
        }
        if(data[k].cover==1)  //这一步的意思是,当所要更改的区间是子区间,那么这个cover等于1就被破坏了,那么我们将这个节点的属性转移给左右节点
        {
          data[2*k].cover=data[k].cover;
          data[2*k+1].cover=data[k].cover;
          data[2*k].inc=data[k].inc;
          data[2*k+1].inc=data[k].inc;
          data[k].cover=0;
          data[k].inc=0;
        }
        mid=(data[k].l+data[k].r)/2;
        if(r<=mid) change(2*k,l,r,x);
        else if (l>mid) change(2*k+1,l,r,x);
        else {change(2*k,l,mid,x); change(2*k+1,mid+1,r,x);}
    }
    void gcd(int k,int l,int r,ll x)   //2操作
    {
     int mid;
     if(data[k].l==l&&data[k].r==r&&data[k].cover==1)
      {
         if(data[k].inc>x)
         {
            data[k].inc=GCD(data[k].inc,x);
            data[k].cover=1;
         }
         return;
      }
       if(data[k].cover==1) //同理如果所要更改的区间是子区间,那么这个cover=1就被破坏了,所以要属性转移
        {
          data[2*k].cover=data[k].cover;
          data[2*k+1].cover=data[k].cover;
          data[2*k].inc=data[k].inc;
          data[2*k+1].inc=data[k].inc;
          data[k].cover=0;
          data[k].inc=0;
        }
     mid=(data[k].l+data[k].r)/2;
     if (r<=mid)gcd(2*k,l,r,x);
     else if(l>mid)gcd(2*k+1,l,r,x);
     else
        {
          gcd(2*k,l,mid,x);
          gcd(2*k+1,mid+1,r,x);
        }
    }

    void sove(int k)   //这个函数是用于最后输出处理的,如果某个节点的cover值等于1,那么就让这个节点以下的所有叶子节点的值都等于inc
    {
     if(data[k].cover==1)
     {
       for(int i=data[k].l;i<=data[k].r;i++)a[i]=data[k].inc;
       return ;
     }
     sove(2*k);
     sove(2*k+1);
    }
    int main()
    {
     int T,n,m,op,l,r;
     ll x;
     cin>>T;
     while(T--)
     {
      memset(a,0,sizeof(a));
      scanf("%d",&n);
      for(int i=1;i<=n;i++)scanf("%I64d",&a[i]);  //以后要记住输入也得用%I64d
      build(1,n,1);
      scanf("%d",&m);
      while(m--)
      {
       scanf("%d%d%d%I64d",&op,&l,&r,&x);
       if(op==1)change(1,l,r,x);
       else if(op==2)gcd(1,l,r,x);
      }
      sove(1);
      for(int i=1;i<=n;i++)
        printf("%I64d ",a[i]);  //输出用I64d;
      printf("\n");
     }
     return 0;
    }

抱歉!评论已关闭.