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\n",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内重复数据出现的少

 

posted @ 2018-05-29 19:59  尹吴潇  阅读(153)  评论(0编辑  收藏  举报