BZOJ4867 Ynoi2017舌尖上的由乃(dfs序+分块)
容易想到用dfs序转化为序列上的问题。考虑分块,对每块排序,修改时对于整块打上标记,边界暴力重构排序数组,询问时二分答案,这样k=sqrt(nlogn)时取最优复杂度nsqrt(nlogn)logn,离跑过去还差一点。二分答案这一部分看上去很难优化,考虑重构时不那么暴力,将要修改的和不要修改的部分分别从已排序数组中提出来,归并即可,这样k=sqrt(n)logn时取最优复杂度nsqrt(n)logn。尽管加了一些奇怪的卡常然而并没有什么卵用,bzoj上根本过不掉。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 100010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,len,p[N],deep[N],dfn[N],id[N],size[N],t,cnt,s; int block,num,pos[N],L[N],R[N],lazy[N]; struct data{int to,nxt,len; }edge[N]; struct data2 { int i,x; bool operator <(const data2&a) const { return x<a.x; } }a[N],u[N],v[N],w[N]; struct data3{int i,j,x,op;}Q[N]; void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;} void dfs(int k) { size[k]=1;dfn[k]=++cnt;id[cnt]=k;s=max(s,deep[k]); for (int i=p[k];i;i=edge[i].nxt) { deep[edge[i].to]=deep[k]+edge[i].len; dfs(edge[i].to); size[k]+=size[edge[i].to]; } } void add(int k,int l,int r,int x) { int n=0,m=0; for (int i=L[k];i<=R[k];i++) if (a[i].i>=l&&a[i].i<=r) u[++n].i=a[i].i,deep[id[a[i].i]]+=x,u[n].x=a[i].x+x; else v[++m]=a[i]; int p=1,q=1; for (int i=L[k];i<=R[k];i++) if (u[p].x<v[q].x&&p<=n||q>m) a[i]=u[p++]; else a[i]=v[q++]; } int calc(int k,int l,int r) { if (pos[l]==pos[r]) { int s=0; for (int i=l;i<=r;i++) if (deep[id[i]]+lazy[pos[l]]<=k) s++; return s; } else { int s=0; for (int i=pos[l]+1;i<pos[r];i++) s+=upper_bound(a+L[i],a+R[i]+1,(data2){0,k-lazy[i]})-a-L[i]; for (int i=l;i<=R[pos[l]];i++) if (deep[id[i]]+lazy[pos[l]]<=k) s++; for (int i=L[pos[r]];i<=r;i++) if (deep[id[i]]+lazy[pos[r]]<=k) s++; return s; } } double complexity(double k,double q){return (m-q)*(n/k+3*k)+q*log(s+(m-q)*(len+1>>1))/log(2)*(n/k*log(n)/log(2)+k);} namespace segmenttree { int L[N<<2],R[N<<2],tree[N<<2],lazy[N<<2]; void build(int k,int l,int r) { L[k]=l,R[k]=r,lazy[k]=0; if (l==r) {tree[k]=deep[id[l]];return;} int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); tree[k]=max(tree[k<<1],tree[k<<1|1]); } void update(int k,int x){tree[k]+=x,lazy[k]+=x;} void down(int k){update(k<<1,lazy[k]),update(k<<1|1,lazy[k]),lazy[k]=0;} void add(int k,int l,int r,int x) { if (L[k]==l&&R[k]==r) {update(k,x);return;} if (lazy[k]) down(k); int mid=L[k]+R[k]>>1; if (r<=mid) add(k<<1,l,r,x); else if (l>mid) add(k<<1|1,l,r,x); else add(k<<1,l,mid,x),add(k<<1|1,mid+1,r,x); tree[k]=max(tree[k<<1],tree[k<<1|1]); } int query(int k,int l,int r) { if (L[k]==l&&R[k]==r) return tree[k]; if (lazy[k]) down(k); int mid=L[k]+R[k]>>1; if (r<=mid) return query(k<<1,l,r); else if (l>mid) return query(k<<1|1,l,r); else return max(query(k<<1,l,mid),query(k<<1|1,mid+1,r)); } } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4867.in","r",stdin); freopen("bzoj4867.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read();len=read(); for (int i=2;i<=n;i++) { int x=read(),y=read(); addedge(x,i,y); } dfs(1);segmenttree::build(1,1,n); int qwq=0; for (int i=1;i<=m;i++) { int op=read(),k=read(),x=read(); if (op==1) qwq++; Q[i].op=op,Q[i].i=dfn[k],Q[i].j=dfn[k]+size[k]-1,Q[i].x=x; } block=1;for (int i=2;i<=n;i++) if (complexity(i,qwq)<complexity(block,qwq)) block=i; num=(n-1)/block+1; for (int i=1;i<=num;i++) { L[i]=(i-1)*block+1,R[i]=min(n,i*block); for (int j=L[i];j<=R[i];j++) pos[j]=i,a[j].i=j,a[j].x=deep[id[j]]; sort(a+L[i],a+R[i]+1); } for (int i=1;i<=m;i++) { int l=Q[i].i,r=Q[i].j,x=Q[i].x; if (Q[i].op==1) { int left=1,right=segmenttree::query(1,l,r),ans=-1; while (left<=right) { int mid=left+right>>1; if (calc(mid,l,r)>=x) ans=mid,right=mid-1; else left=mid+1; } printf("%d\n",ans); } else { segmenttree::add(1,l,r,x); if (pos[l]==pos[r]) add(pos[l],l,r,x); else { for (int i=pos[l]+1;i<pos[r];i++) lazy[i]+=x; add(pos[l],l,R[pos[l]],x),add(pos[r],L[pos[r]],r,x); } } } return 0; }