• hdu 5381


    题解:

    还是比较水的一道题

    首先可以发现每个数最多被除log次,所以有连续一段相同

    然后我想的是变成矩形统计前缀和问题用主席树来维护

    然后发现这题很卡空间

    qwq acm依旧很多64mb的题

    首先比较重要的一点是

    这题如果不用标记永久化

    需要用到down

    主席树down需要新开节点(随意yy一下就知道了)

    当然为了节省空间我们选择标记永久化

    这时候我们就要记录两个标记

    一个代表不用传递到儿子的data

    一个代表要传递到儿子的lazy

    至于为什么自己想一下就知道了

    另外这题的方法应该是将询问离线(离线很重要啊)

    然后把每个询问拆成两个,sort一遍再做

    这样就是线段树的空间了

    正解:

    另外这题应该还有一个做法,就是直接对整个序列建线段树是在线的(我觉得这个应该才算正解)

    然后维护每个区间中子区间gcd的和,和边界区间对应的log个数值,以及对应个数

    然后区间合并显然可以通过这些信息来维护

    而查询的时候先找出对应区间,用和updata一样的方法维护答案

    不过这样updata的时候应该是logn^2的

    所以时间应该是nlogn^3的

    线段树很多时候就是像这样利用区间合并 下次应该要注意一下

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define IL inline
    #define rint register int 
    #define rep(i,h,t) for (rint i=h;i<=t;i++)
    #define dep(i,t,h) for (rint i=t;i>=h;i--)
    #define mid ((h+t)/2)
    IL int max(int x,int y)
    {
      if (x>y) return(x);
      else return(y);
    }
    IL int min(int x,int y)
    {
      if (x<y) return(x);
      else return(y);
    }
    IL void swap(int &x,int &y)
    {
      int tmp=x;x=y,y=tmp;
    }
    struct re{
      int a,b;
    };
    vector<re> ve,ve1;
    const int N=1.1e4;
    const int N2=3e6;
    int n,m,a[N],root[N],cnt,ls[N2],rs[N2],lazy[N2];
    ll data[N2];
    int gcd(int x,int y)
    {
      if(!y) return(x);
      return(gcd(y,x%y));
    }
    void change(int last,int &x,int h,int t,int h1,int t1,int k)
    {
      x=++cnt;
      ls[x]=ls[last]; rs[x]=rs[last]; lazy[x]=lazy[last]; data[x]=data[last];
      data[x]+=1ll*k*(min(t,t1)-max(h,h1)+1);
      if (h1<=h&&t<=t1)
      {
        lazy[x]+=k; return;
      }
      if (h1<=mid) change(ls[last],ls[x],h,mid,h1,t1,k);
      if (mid<t1) change(rs[last],rs[x],mid+1,t,h1,t1,k);
    }
    ll query2(int x,int h,int t,int h1,int t1,int k)
    {
      if (h1<=h&&t<=t1) return(data[x]+k*(t-h+1));
      ll ans=0;
      if (h1<=mid) ans+=query2(ls[x],h,mid,h1,t1,k+lazy[x]);
      if (mid<t1) ans+=query2(rs[x],mid+1,t,h1,t1,k+lazy[x]);
      return(ans);
    }
    IL ll query(int x,int h,int t,int h1,int t1)
    {
      if (h1>t1) return(0);
      return(query2(x,h,t,h1,t1,0));
    }
    int main()
    {
      freopen("1.in","r",stdin);
      freopen("1.out","w",stdout);
      int T;
      scanf("%d",&T);
      while (scanf("%d",&n)!=EOF)
      {
        rep(i,1,n) scanf("%d",&a[i]);
        cnt=0;
        memset(ls,0,sizeof(ls));
        memset(rs,0,sizeof(rs));
        memset(lazy,0,sizeof(lazy));
        ve.clear(); 
        rep(i,1,n)
        {
          ve1.clear();
          int tmp=a[i],last=i;
          root[i]=root[i-1];
          ve1.push_back((re){i,tmp});
          int len=ve.size()-1;
          rep(j,0,len)
          {
            int tmp2=tmp;
            tmp=gcd(tmp,ve[j].b);
            if (tmp2!=tmp)
            { 
              ve1.push_back((re){ve[j].a,tmp});
              change(root[i],root[i],1,n,ve[j].a+1,last,tmp2);
              last=ve[j].a;
            }
          }
          change(root[i],root[i],1,n,1,last,tmp);
          ve.swap(ve1); 
        }
        scanf("%d",&m);
        rep(i,1,m)
        {
          int l,r;
          scanf("%d%d",&l,&r);
          printf("%lld
    ",query(root[r],1,n,1,r)-query(root[r],1,n,1,l-1)); 
        }
      }
      return 0; 
    }
  • 相关阅读:
    简单的结账功能(可用于各种结账)
    有关菜单进行“估清”的功能
    在线客服~~
    在windows下安装GIT
    GIT之二 基础篇(2)
    简单模仿javascript confirm方法的例子
    微信公众平台开发 第三篇
    微信公众平台开发 第二篇
    微信公众平台开发 第一篇
    GIT之二 基础篇(1)
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/9103014.html
Copyright © 2020-2023  润新知