特技树链剖分
线段树划分时按照子树的size平分
听说会变成一个log的,实际效果不明
BZOJ1036
#include <cstdio> #include <iostream> #include <cmath> #define LL long long using namespace std; struct treenode{ LL sum,maxi; int mid,l,r,lc,rc; }tr[400001]; int size[200001],nd[200001],next[400001],dep[200001],des[400001],fa[200001]; int heav[200001],top[200001],ori[200001],cnt,id[200001]; int a[200001],root[200001],n,t1,t2,dsize[200001]; char st[201]; void addedge(int x,int y){ next[++cnt]=nd[x];des[cnt]=y;nd[x]=cnt; } void dfs1(int po){ size[po]=1;int maxi=0; for (int p=nd[po];p!=-1;p=next[p]) if (!dep[des[p]]){ dep[des[p]]=dep[po]+1; fa[des[p]]=po; dfs1(des[p]); size[po]+=size[des[p]]; if (size[des[p]]>maxi){ maxi=size[des[p]]; heav[po]=des[p]; } } } void dfs2(int po,int tp){ top[po]=tp;ori[++cnt]=po;id[po]=cnt;dsize[po]=1; if (heav[po]) dfs2(heav[po],tp); for (int p=nd[po];p!=-1;p=next[p]) if (des[p]!=heav[po]&&dep[des[p]]==dep[po]+1){ dfs2(des[p],des[p]); dsize[po]+=size[des[p]]; } } void update(int po){ tr[po].maxi=max(tr[tr[po].lc].maxi,tr[tr[po].rc].maxi); tr[po].sum=tr[tr[po].lc].sum+tr[tr[po].rc].sum; } void build(int l,int r){ tr[++cnt].l=l;tr[cnt].r=r; if (l==r){ tr[cnt].sum=tr[cnt].maxi=a[ori[l]]; return; } int totd=0,mini=1e9,t=0;for (int i=l;i<=r;i++) totd+=dsize[ori[i]]; for (int i=l;i<r;i++){ t+=dsize[ori[i]]; if (fabs(totd-2*t)<mini){ mini=fabs(totd-2*t); tr[cnt].mid=i; } } t=cnt; tr[t].lc=cnt+1; build(l,tr[t].mid); tr[t].rc=cnt+1; build(tr[t].mid+1,r); update(t); } void edi(int po,int tar,int num){ if (tr[po].l==tr[po].r){ tr[po].sum=tr[po].maxi=num; return; } if (tar<=tr[po].mid) edi(tr[po].lc,tar,num);else edi(tr[po].rc,tar,num); update(po); } LL segsum(int po,int tarl,int tarr){ if (tarl==tr[po].l&&tarr==tr[po].r) return(tr[po].sum); LL ret=0; if (tarl<=tr[po].mid) ret+=segsum(tr[po].lc,tarl,min(tr[po].mid,tarr)); if (tarr>tr[po].mid) ret+=segsum(tr[po].rc,max(tr[po].mid+1,tarl),tarr); return(ret); } LL quesum(int x,int y){ LL ret=0; while (top[x]!=top[y]){ if (dep[top[x]]<dep[top[y]]) swap(x,y); ret+=segsum(root[top[x]],id[top[x]],id[x]); x=fa[top[x]]; } if (dep[x]<dep[y]) swap(x,y); ret+=segsum(root[top[x]],id[y],id[x]); return(ret); } LL segmax(int po,int tarl,int tarr){ if (tarl==tr[po].l&&tarr==tr[po].r) return(tr[po].maxi); LL ret=-1e9; if (tarl<=tr[po].mid) ret=max(segmax(tr[po].lc,tarl,min(tr[po].mid,tarr)),ret); if (tarr>tr[po].mid) ret=max(segmax(tr[po].rc,max(tr[po].mid+1,tarl),tarr),ret); return(ret); } LL quemax(int x,int y){ LL ret=-1e9; while (top[x]!=top[y]){ if (dep[top[x]]<dep[top[y]]) swap(x,y); ret=max(segmax(root[top[x]],id[top[x]],id[x]),ret); x=fa[top[x]]; } if (dep[x]<dep[y]) swap(x,y); ret=max(segmax(root[top[x]],id[y],id[x]),ret); return(ret); } int main(){ scanf("%d",&n); for (int i=1;i<=n;i++) nd[i]=-1; cnt=0; for (int i=1;i<n;i++){ scanf("%d%d",&t1,&t2); addedge(t1,t2);addedge(t2,t1); } for (int i=1;i<=n;i++) scanf("%d",&a[i]); cnt=0; dep[1]=1; dfs1(1); dfs2(1,1); cnt=0; for (int i=1;i<=n;i++) if (top[ori[i]]!=top[ori[i+1]]) root[top[ori[i]]]=cnt+1, build(id[top[ori[i]]],i); int q; scanf("%d",&q); while (q--){ scanf("%s%d%d",&st,&t1,&t2); if (st[1]=='H') edi(root[top[t1]],id[t1],t2); if (st[1]=='M') printf("%lld\n",quemax(t1,t2)); if (st[1]=='S') printf("%lld\n",quesum(t1,t2)); } }