• BZOJ 4127 Abs 树链剖分


    题解:

    首先比较显然的是每个点只会有一个点变正

    然后我并没有想出来怎么搞

    我想的是是用主席树来可持久化树链剖分然后二分

    但是这样空间是nlogn^2的跟个傻逼一样

    比较优的做法是用线段树维护负数的最大值

    然后 我们继续深入的条件是这个点会被修改

    也就是说logn时间我们必定搞完了一个点

    这种线段树的思想也是很重要的

    所以这样时间是nlogn的

    稍微说一下代码的细节

    维护一个区间内小于0的数目(用来更新sum),sum

    代码:

    我很zz的把INF设成1e9

    没有考虑到lazy的范围。。

    手动测了一下跑的还是挺快的,比网上大多数的快

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define IL inline
    #define rint register int
    #define ls (x<<1)
    #define rs ((x<<1)|1)
    #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)
    const ll INF=1e17;
    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;
    }
    char ss[1<<27],*A=ss,*B=ss;
    IL char gc()
    {
      return A==B&&(B=(A=ss)+fread(ss,1,1<<27,stdin),A==B)?EOF:*A++;
    }
    template<class T>void read(T &x)
    {
      rint f=1,c; while (c=gc(),c<48||57<c) if (c=='-') f=-1; x=c^48;
      while (c=gc(),47<c&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f;
    }
    const int N=1e5+1e4;
    struct re{
      int a,b;
    }a[N*2];
    int n,m,num2,head[N],v[N],top[N],dep[N],fa[N],son[N],size[N],id[N],real2[N],l,vv[N];
    ll sum[N*4],minn[N*4],num[N*4],lazy[N*4];
    void arr(int x,int y)
    {
      a[++l].a=head[x];
      a[l].b=y;
      head[x]=l;
    }
    void dfs1(int x,int fa1)
    {
      fa[x]=fa1; dep[x]=dep[fa1]+1;
      son[x]=-1; size[x]=1;
      int u=head[x];
      while (u)
      {
        int v=a[u].b;
        if (v!=fa1)
        {
          dfs1(v,x);
          size[x]+=size[v];
          if (son[x]==-1||size[son[x]]<size[v])
            son[x]=v;
        }
        u=a[u].a;
      }
    }
    void dfs2(int x,int y)
    {
      top[x]=y; num2++;
      id[x]=num2; real2[num2]=x; v[num2]=vv[x];
      if (son[x]==-1) return;
      dfs2(son[x],y);
      int u=head[x];
      while (u)
      {
        int v=a[u].b;
        if (v!=fa[x]&&v!=son[x])
          dfs2(v,v);
        u=a[u].a;
      }
    }
    IL void down(int x,int h,int t)
    {
      if(!lazy[x]) return;
      int k=lazy[x];
      minn[ls]+=k;
      minn[rs]+=k;
      sum[ls]+=1ll*(mid-h+1-2*num[ls])*k;
      sum[rs]+=1ll*(t-mid-2*num[rs])*k; 
      lazy[ls]+=k; lazy[rs]+=k;
      lazy[x]=0;
    }
    IL void updata(int x)
    {
      sum[x]=sum[ls]+sum[rs];
      minn[x]=max(minn[ls],minn[rs]);
      num[x]=num[ls]+num[rs];
    }
    void build(int x,int h,int t)
    {
      if (h==t)
      {
        if (v[h]<0) minn[x]=v[h],num[x]=1;
        else minn[x]=-INF,num[x]=0;
        sum[x]=abs(v[h]);
        return;
      }
      build(ls,h,mid); build(rs,mid+1,t);
      updata(x);
    }
    void change(int x,int h,int t,int h1,int t1,int k)
    {
      if (minn[x]+k>=0)
      {
        if (h==t)
        {
          sum[x]=minn[x]+k;
          minn[x]=-INF;
          num[x]=0;
          return;
        }
        down(x,h,t); 
        if (h1<=mid) change(ls,h,mid,h1,t1,k);
        if (mid<t1) change(rs,mid+1,t,h1,t1,k);
        updata(x);
      } else
      {
        if(h1<=h&&t<=t1)
        {
          lazy[x]+=k; sum[x]+=1ll*(t-h+1-2*num[x])*k;
          minn[x]+=k;
          return;
        }
        down(x,h,t); 
        if (h1<=mid) change(ls,h,mid,h1,t1,k);
        if (mid<t1) change(rs,mid+1,t,h1,t1,k);
        updata(x);
      }
    }
    ll query(int x,int h,int t,int h1,int t1)
    {
      if (h1<=h&&t<=t1) return(sum[x]);
      down(x,h,t); 
      ll ans=0;
      if (h1<=mid) ans+=query(ls,h,mid,h1,t1);
      if (mid<t1) ans+=query(rs,mid+1,t,h1,t1);
      return(ans);
    }
    void change2(int x,int y,int k)
    {
      int f1=top[x],f2=top[y];
      while (f1!=f2)
      {
        if (dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
        change(1,1,n,id[f1],id[x],k);
        x=fa[f1]; f1=top[x];
      } 
      if (dep[x]<dep[y]) swap(x,y);
      change(1,1,n,id[y],id[x],k);
    }
    ll query2(int x,int y)
    {
      ll ans=0,f1=top[x],f2=top[y];
      while (f1!=f2)
      {
        if (dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
        ans+=query(1,1,n,id[f1],id[x]);
        x=fa[f1]; f1=top[x];
      }
      if (dep[x]<dep[y]) swap(x,y);
      ans+=query(1,1,n,id[y],id[x]); 
      return(ans);
    }
    int main()
    {
      freopen("1.in","r",stdin);
      freopen("1.out","w",stdout);
      read(n); read(m);
      rep(i,1,n) read(vv[i]);
      rep(i,1,n-1)
      {
        int x,y;
        read(x); read(y); arr(x,y); arr(y,x);
      }
      dfs1(1,0);
      dfs2(1,1);
      build(1,1,n);
      rep(i,1,m)
      {
        int x,y,z,w;
        read(x); read(y); read(z);
        if (x==2)
        {
          printf("%lld
    ",query2(y,z));
        } else
        {
          read(w);
          change2(y,z,w);
        }
      }
      return 0; 
    }

    maker:

    #include <bits/stdc++.h>
    using namespace std;
    const int mo=1e6;
    int main()
    {
      freopen("1.in","w",stdout); 
      srand(time(0)^size_t(new char));
      int n=1,m=10000;
      cout<<n<<" "<<m<<endl;
      for (int i=1;i<=n;i++)
      {
        int x=(rand()*rand())%mo;
        int y=rand()%2;
        if (!y) x=-x;
        cout<<x<<" ";
      }
      cout<<endl;
      for (int i=2;i<=n;i++)
      {
        int x=rand()%(i-1)+1;
        cout<<x<<" "<<i<<endl;
      }
      cout<<endl;
      for (int i=1;i<=m;i++)
      {
        int x=rand()%2+1;
        int y=rand()%n+1,z=rand()%n+1,w=(rand()*rand())%mo;
        if(y>z) swap(y,z);
        if (x==1)
        {
          cout<<x<<" "<<y<<" "<<z<<" "<<w<<endl;
        } else
        {
          cout<<x<<" "<<y<<" "<<z<<endl; 
        }
      }
    }

    注意  srand(time(0)^size_t(new char));

    这句能使得在1s内重复数据出现的少

  • 相关阅读:
    斐波那契数列实现方式,以及递归和非递归时间对比
    月份与季节
    时针与分针夹角
    二叉树非递归遍历 以及二叉树节点删除思路
    向左向右 —折半查找(二分法)
    c语言之字符串及字符集简介
    c语言之排序
    C语言代码页 预处理 和宏 结构体 共用体 枚举 指针简绍
    C语言之函数调用约定,递归,数组简介
    C语言之条件判断
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/9107599.html
Copyright © 2020-2023  润新知