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