树链剖分
cogs||bzoj1036 树的统计count
题目大意:模板题。
思路:模板题。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #define maxnode 30001 #define mid (l+r)/2 #define inf 2100000000LL using namespace std; struct use{ int fa,top,siz,son,dep,tid; }tree[maxnode]={0}; struct seg{ int maxn,sum; }t[maxnode*4]={0}; int point[maxnode*2]={0},next[maxnode*2]={0},en[maxnode*2],tot=0,tt[maxnode],wi[maxnode]; char ch[10]; bool visit[maxnode]={false}; void add(int st,int enn) { ++tot;next[tot]=point[st];point[st]=tot;en[tot]=enn; ++tot;next[tot]=point[enn];point[enn]=tot;en[tot]=st; } void findc(int u,int fa,int depth) { int i,j,maxsiz=0; visit[u]=true;tree[u].siz=1; tree[u].fa=fa;tree[u].dep=depth; for (i=point[u];i;i=next[i]) if (!visit[en[i]]) { j=en[i];findc(j,u,depth+1); tree[u].siz+=tree[j].siz; if (tree[j].siz>maxsiz) { maxsiz=tree[j].siz; tree[u].son=j; } } } void connc(int u,int top) { int i,j; visit[u]=false;tree[u].top=top; tree[u].tid=++tot;tt[tot]=u; if (tree[u].son) connc(tree[u].son,top); for (i=point[u];i;i=next[i]) if (visit[en[i]]) { j=en[i];connc(j,j); } } void updata(int i) { t[i].maxn=max(t[i*2].maxn,t[i*2+1].maxn); t[i].sum=t[i*2].sum+t[i*2+1].sum; } void build(int i,int l,int r) { if (l==r) { t[i].maxn=t[i].sum=wi[tt[l]];return; } build(i*2,l,mid);build(i*2+1,mid+1,r); updata(i); } void change(int i,int l,int r,int x,int y) { if (l==r) { t[i].maxn=t[i].sum=y;return; } if (x<=mid) change(i*2,l,mid,x,y); else change(i*2+1,mid+1,r,x,y); updata(i); } int tmax(int i,int l,int r,int ll,int rr) { int maxn; if (ll<=l&&r<=rr) return t[i].maxn; maxn=-inf; if (ll<=mid) maxn=max(maxn,tmax(i*2,l,mid,ll,rr)); if (rr>mid) maxn=max(maxn,tmax(i*2+1,mid+1,r,ll,rr)); return maxn; } int tsum(int i,int l,int r,int ll,int rr) { int sum=0; if (ll<=l&&r<=rr) return t[i].sum; if (ll<=mid) sum+=tsum(i*2,l,mid,ll,rr); if (rr>mid) sum+=tsum(i*2+1,mid+1,r,ll,rr); return sum; } int qmax(int x,int y) { int maxn; maxn=-inf; while(tree[x].top!=tree[y].top) { if (tree[tree[x].top].dep<tree[tree[y].top].dep) swap(x,y); maxn=max(maxn,tmax(1,1,tot,tree[tree[x].top].tid,tree[x].tid)); x=tree[tree[x].top].fa; } if (tree[x].dep<tree[y].dep) swap(x,y); maxn=max(maxn,tmax(1,1,tot,tree[y].tid,tree[x].tid)); return maxn; } int qsum(int x,int y) { int sum=0; while(tree[x].top!=tree[y].top) { if (tree[tree[x].top].dep<tree[tree[y].top].dep) swap(x,y); sum+=tsum(1,1,tot,tree[tree[x].top].tid,tree[x].tid); x=tree[tree[x].top].fa; } if (tree[x].dep<tree[y].dep) swap(x,y); sum+=tsum(1,1,tot,tree[y].tid,tree[x].tid); return sum; } int main() { freopen("bzoj_1036.in","r",stdin); freopen("bzoj_1036.out","w",stdout); int i,j,n,m,a,b,ans; scanf("%d",&n); for (i=1;i<n;++i) { scanf("%d%d",&a,&b); add(a,b); } findc(1,0,1); tot=0;connc(1,1); for (i=1;i<=n;++i) scanf("%d",&wi[i]); build(1,1,tot); scanf("%d",&m); for (i=1;i<=m;++i) { scanf("%*c%s",&ch);scanf("%d%d",&a,&b); if (ch[0]=='C') change(1,1,tot,tree[a].tid,b); else { if (ch[1]=='M') ans=qmax(a,b); else ans=qsum(a,b); printf("%d\n",ans); } } fclose(stdin); fclose(stdout); }
cogs 树的维护
题目大意:模板题+区间取反。
思路:取反的时候是纯线段树操作,有很多细节:insert、updata和ask的时候都要考虑delta的取值。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #define maxnode 10001 #define mid (l+r)/2 #define inf 2100000000 using namespace std; int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2],va[maxnode*2],bi[maxnode*2],tt[maxnode]={0},wi[maxnode]; char ch[10]; struct use{ int maxn,minn,delta,sig; }t[maxnode*4]; void updata(int i) { t[i].maxn=max((t[i].sig==t[i*2].sig ? t[i*2].maxn : -t[i*2].minn),(t[i].sig==t[i*2+1].sig ? t[i*2+1].maxn : -t[i*2+1].minn)); t[i].minn=min((t[i].sig==t[i*2].sig ? t[i*2].minn : -t[i*2].maxn),(t[i].sig==t[i*2+1].sig ? t[i*2+1].minn : -t[i*2+1].maxn)); } void build(int i,int l,int r) { if (l==r) { t[i].maxn=t[i].minn=wi[tt[l]]; t[i].delta=t[i].sig=0;return; } build(i*2,l,mid);build(i*2+1,mid+1,r); updata(i); } void paint(int i) { t[i].sig=1-t[i].sig;t[i].delta=1-t[i].delta; } void pushdown(int i) { if (t[i].delta) { paint(i*2);paint(i*2+1); t[i].delta=0; } } void tchange(int i,int l,int r,int x,int y) { if (l==r) { if (t[i].sig) t[i].maxn=t[i].minn=-y; else t[i].maxn=t[i].minn=y; return; } pushdown(i); if (x<=mid) tchange(i*2,l,mid,x,y); else tchange(i*2+1,mid+1,r,x,y); updata(i); } void tneg(int i,int l,int r,int ll,int rr) { if (ll<=l&&r<=rr) { paint(i);return; } pushdown(i); if (ll<=mid) tneg(i*2,l,mid,ll,rr); if (rr>mid) tneg(i*2+1,mid+1,r,ll,rr); updata(i); } int tmax(int i,int l,int r,int ll,int rr) { int maxn; if (ll<=l&&r<=rr) { if (t[i].sig) return -t[i].minn; else return t[i].maxn; } maxn=-inf;pushdown(i); if (ll<=mid) maxn=max(maxn,tmax(i*2,l,mid,ll,rr)); if (rr>mid) maxn=max(maxn,tmax(i*2+1,mid+1,r,ll,rr)); return maxn; } struct lp{ int fa[maxnode],son[maxnode],dep[maxnode],top[maxnode],siz[maxnode],tid[maxnode],edge[maxnode],tot; bool visit[maxnode]; void add(int st,int enn,int vaa,int i) { ++tot;next[tot]=point[st];point[st]=tot;en[tot]=enn;va[tot]=vaa;bi[tot]=i; ++tot;next[tot]=point[enn];point[enn]=tot;en[tot]=st;va[tot]=vaa;bi[tot]=i; } void dfs1(int u,int ff,int depth,int vaa,int ii) { int i,j,maxsiz=0; visit[u]=true;fa[u]=ff;dep[u]=depth; son[u]=0;siz[u]=1;wi[u]=vaa;edge[ii]=u; for (i=point[u];i;i=next[i]) if (!visit[j=en[i]]) { dfs1(j,u,depth+1,va[i],bi[i]); siz[u]+=siz[j]; if (siz[j]>maxsiz) { maxsiz=siz[j];son[u]=j; } } } void dfs2(int u,int anc) { int i,j; visit[u]=false;top[u]=anc; tid[u]=++tot;tt[tot]=u; if (son[u]) dfs2(son[u],anc); for (i=point[u];i;i=next[i]) if (visit[j=en[i]]) dfs2(j,j); } void change(int a,int b) { a=tid[edge[a]]; tchange(1,1,tot,a,b); } void neg(int a,int b) { while(top[a]!=top[b]) { if (dep[top[a]]<dep[top[b]]) swap(a,b); tneg(1,1,tot,tid[top[a]],tid[a]); a=fa[top[a]]; } if (dep[a]>dep[b]) swap(a,b); if (a!=b) tneg(1,1,tot,tid[son[a]],tid[b]); } void qmax(int a,int b) { int maxn; maxn=-inf; while(top[a]!=top[b]) { if (dep[top[a]]<dep[top[b]]) swap(a,b); maxn=max(maxn,tmax(1,1,tot,tid[top[a]],tid[a])); a=fa[top[a]]; } if (dep[a]>dep[b]) swap(a,b); if (a!=b) maxn=max(maxn,tmax(1,1,tot,tid[son[a]],tid[b])); printf("%d\n",maxn); } }tree; int main() { freopen("maintaintree.in","r",stdin); freopen("maintaintree.out","w",stdout); int n,i,j,a,b,c; scanf("%d",&n);tree.tot=0; memset(tree.visit,false,sizeof(tree.visit)); for (i=1;i<n;++i) { scanf("%d%d%d",&a,&b,&c); tree.add(a,b,c,i); } tree.dfs1(1,0,1,0,0); tree.tot=0;tree.dfs2(1,1); build(1,1,tree.tot); while(scanf("%*c%s",&ch)==1) { if (ch[0]=='D') break; scanf("%d%d",&a,&b); if (ch[0]=='C') tree.change(a,b); if (ch[0]=='N') tree.neg(a,b); if (ch[0]=='Q') tree.qmax(a,b); } fclose(stdin); fclose(stdout); }
bzoj3083 遥远的国度
题目大意:换父亲、改点权、子树最小值。
思路:换父亲是三种情况的分类讨论:我们并不是真的换父亲、重新建树。当前根root,子树的根节点x。1)如果root=x,就查询整棵树;2)如果当lca(root,x)!=x,就查询x的子树;3)如果当lca(root,x)=x,就查询x的儿子中离root最近的那个儿子在整棵树中的补集。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxnode 100001 #define inf 0x7fffffff using namespace std; struct use{ int delta,minn; }t[maxnode*4]={0}; int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},fy[maxnode]={0},tot=0,id[maxnode]={0}; void updata(int i) { t[i].minn=min(t[i*2].minn,t[i*2+1].minn); } void pushdown(int i) { if (t[i].delta) { t[i*2].minn=t[i*2].delta=t[i].delta; t[i*2+1].minn=t[i*2+1].delta=t[i].delta; t[i].delta=0; } } void build(int i,int l,int r) { int mid; if (l==r) { t[i].delta=0;t[i].minn=fy[id[l]];return; } mid=(l+r)/2; build(i*2,l,mid);build(i*2+1,mid+1,r); updata(i); } void tch(int i,int l,int r,int ll,int rr,int v) { int mid; if (ll<=l&&r<=rr) { t[i].delta=t[i].minn=v;return; } mid=(l+r)/2; pushdown(i); if (ll<=mid) tch(i*2,l,mid,ll,rr,v); if (rr>mid) tch(i*2+1,mid+1,r,ll,rr,v); updata(i); } int task(int i,int l,int r,int ll,int rr) { int mid,ans; if (ll<=l&&r<=rr) return t[i].minn; mid=(l+r)/2;ans=inf;pushdown(i); if (ll<=mid) ans=min(ans,task(i*2,l,mid,ll,rr)); if (rr>mid) ans=min(ans,task(i*2+1,mid+1,r,ll,rr)); return ans; } struct lp{ int fa[maxnode][20],son[maxnode],dep[maxnode],top[maxnode],siz[maxnode],tid[maxnode],ri[maxnode]; bool visit[maxnode]; void add(int st,int enn) { ++tot;next[tot]=point[st];point[st]=tot;en[tot]=enn; ++tot;next[tot]=point[enn];point[enn]=tot;en[tot]=st; } void dfs1(int u,int ff,int depth) { int i,j,maxsiz=0; visit[u]=true;fa[u][0]=ff;dep[u]=depth; son[u]=0;siz[u]=1; for (i=1;i<=18;++i) fa[u][i]=fa[fa[u][i-1]][i-1]; for (i=point[u];i;i=next[i]) { if (!visit[j=en[i]]) { dfs1(j,u,depth+1); siz[u]+=siz[j]; if (siz[j]>maxsiz) { maxsiz=siz[j];son[u]=j; } } } } void dfs2(int u,int anc) { int i,j; visit[u]=false;top[u]=anc; tid[u]=++tot;id[tot]=u; if (son[u]) dfs2(son[u],anc); for (i=point[u];i;i=next[i]) { if (visit[j=en[i]]) dfs2(j,j); } ri[u]=tot; } int lca(int a,int b) { int i,j; if (dep[a]>dep[b]) swap(a,b); for (i=18;i>=0;--i) if (dep[a]<=dep[fa[b][i]]) b=fa[b][i]; if (a==b) return a; for (i=18;i>=0;--i) { if (fa[a][i]!=fa[b][i]) { a=fa[a][i];b=fa[b][i]; } } return fa[a][0]; } void change(int a,int b,int v) { int i,j; while(top[a]!=top[b]) { if (dep[top[a]]<dep[top[b]]) swap(a,b); tch(1,1,tot,tid[top[a]],tid[a],v); a=fa[top[a]][0]; } if (dep[a]>dep[b]) swap(a,b); tch(1,1,tot,tid[a],tid[b],v); } int ask(int a,int root) { int ans,ll,i,j; if (a==root) return task(1,1,tot,1,tot); ll=lca(a,root); if (ll!=a) return task(1,1,tot,tid[a],ri[a]); else { ans=inf;j=root; for (i=18;i>=0;--i) if (dep[fa[j][i]]>dep[a]) j=fa[j][i]; ans=min((tid[j]>1 ? task(1,1,tot,1,tid[j]-1) : inf),(ri[j]<tot ? task(1,1,tot,ri[j]+1,tot) : inf)); return ans; } } }tree; int main() { int u,v,n,m,i,j,opt,root,p1,p2,ans; scanf("%d%d",&n,&m); for (i=1;i<n;++i) { scanf("%d%d",&u,&v); tree.add(u,v); } for (i=1;i<=n;++i) scanf("%d",&fy[i]); scanf("%d",&root);tot=0; memset(tree.visit,false,sizeof(tree.visit)); tree.dfs1(root,0,1); tree.dfs2(root,root); build(1,1,tot); for (i=1;i<=m;++i) { scanf("%d",&opt); if (opt==1) scanf("%d",&root); if (opt==2) { scanf("%d%d%d",&p1,&p2,&v); tree.change(p1,p2,v); } if (opt==3) { scanf("%d",&p1); ans=tree.ask(p1,root); printf("%d\n",ans); } } }
bzoj2243 染色
题目大意:区间修改、区间不同子段的个数。
思路:线段树上的操作。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxnode 100001 using namespace std; struct use{ int lc,rc,sum,delta; }t[maxnode*4]={0}; int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},id[maxnode]={0},tot=0,fy[maxnode]={0}; void updata(int i) { t[i].lc=t[i*2].lc;t[i].rc=t[i*2+1].rc; t[i].sum=t[i*2].sum+t[i*2+1].sum; if (t[i*2].rc==t[i*2+1].lc) --t[i].sum; } void pushdown(int i) { if (t[i].delta>=0) { t[i*2].lc=t[i*2].rc=t[i*2].delta=t[i].delta;t[i*2].sum=1; t[i*2+1].lc=t[i*2+1].rc=t[i*2+1].delta=t[i].delta;t[i*2+1].sum=1; t[i].delta=-1; } } void build(int i,int l,int r) { int mid; if (l==r) { t[i].lc=t[i].rc=fy[id[l]];t[i].sum=1;t[i].delta=-1;return; } mid=(l+r)/2; build(i*2,l,mid);build(i*2+1,mid+1,r); updata(i);t[i].delta=-1; } void tch(int i,int l,int r,int ll,int rr,int v) { int mid; if (ll<=l&&r<=rr) { t[i].lc=t[i].rc=t[i].delta=v;t[i].sum=1;return; } mid=(l+r)/2;pushdown(i); if (ll<=mid) tch(i*2,l,mid,ll,rr,v); if (rr>mid) tch(i*2+1,mid+1,r,ll,rr,v); updata(i); } struct use task(int i,int l,int r,int ll,int rr) { int mid,sum=0; bool u1=false,u2=false; struct use n1,n2,ans; if (ll<=l&&r<=rr) return t[i]; mid=(l+r)/2;pushdown(i); if (ll<=mid) {u1=true;n1=task(i*2,l,mid,ll,rr);} if (rr>mid) {u2=true;n2=task(i*2+1,mid+1,r,ll,rr);} if (u1) ans.lc=n1.lc; else ans.lc=n2.lc; if (u2) ans.rc=n2.rc; else ans.rc=n1.rc; ans.sum=(u1 ? n1.sum : 0)+(u2 ? n2.sum : 0); if (u1&&u2&&n1.rc==n2.lc) --ans.sum; return ans; } struct lp{ int fa[maxnode],dep[maxnode],son[maxnode],siz[maxnode],top[maxnode],tid[maxnode]; bool visit[maxnode]; void add(int u,int v) { ++tot;next[tot]=point[u];point[u]=tot;en[tot]=v; ++tot;next[tot]=point[v];point[v]=tot;en[tot]=u; } void dfs1(int u,int ff,int depth) { int i,j,maxsiz=0; fa[u]=ff;dep[u]=depth;son[u]=0; visit[u]=true;siz[u]=1; for (i=point[u];i;i=next[i]) { if (!visit[j=en[i]]) { dfs1(j,u,depth+1); siz[u]+=siz[j]; if (siz[j]>maxsiz) { maxsiz=siz[j];son[u]=j; } } } } void dfs2(int u,int anc) { int i,j; tid[u]=++tot;top[u]=anc; visit[u]=false;id[tot]=u; if (son[u]) dfs2(son[u],anc); for (i=point[u];i;i=next[i]) { if (visit[j=en[i]]) dfs2(j,j); } } void change(int a,int b,int v) { int i; while(top[a]!=top[b]) { if (dep[top[a]]<dep[top[b]]) swap(a,b); tch(1,1,tot,tid[top[a]],tid[a],v); a=fa[top[a]]; } if (dep[a]>dep[b]) swap(a,b); tch(1,1,tot,tid[a],tid[b],v); } int ask(int a,int b) { int ans=0,co[2],kk=0; struct use i; co[0]=co[1]=-1; while(top[a]!=top[b]) { if (dep[top[a]]<dep[top[b]]) { swap(a,b);kk^=1; } i=task(1,1,tot,tid[top[a]],tid[a]); ans+=i.sum; if (co[kk]==i.rc) --ans; co[kk]=i.lc; a=fa[top[a]]; } if (dep[a]>dep[b]) { swap(a,b);kk^=1; } i=task(1,1,tot,tid[a],tid[b]); ans+=i.sum; if (co[kk]==i.lc) --ans; co[kk]=i.rc; if (co[kk]==co[kk^1]) --ans; return ans; } }tree; int main() { int n,m,i,j,u,v,t; char ch; scanf("%d%d",&n,&m); for (i=1;i<=n;++i) scanf("%d",&fy[i]); for (i=1;i<n;++i) { scanf("%d%d",&u,&v);tree.add(u,v); } memset(tree.visit,false,sizeof(tree.visit)); tree.dfs1(1,0,1);tot=0; tree.dfs2(1,1);build(1,1,tot); for (i=1;i<=m;++i) { while(scanf("%c",&ch)==1) { if (ch=='C'||ch=='Q') break; } if (ch=='C') { scanf("%d%d%d",&u,&v,&t); tree.change(u,v,t); } else { scanf("%d%d",&u,&v); printf("%d\n",tree.ask(u,v)); } } }
codevs3305&&3306 水果姐逛水果街系列
题目大意:查询树上从a到b的路径中后面减前面的最大差值(+单点修改)。
思路:链剖+线段树的操作,稍复杂一点,分类讨论。有点像上一题。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxnode 200001 #define inf 2100000000 using namespace std; int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},fy[maxnode]={0},id[maxnode]={0},tot=0; struct use{ int maxn,minn,mac,mic; }t[maxnode*4]; void updata(int i) { t[i].mac=max(t[i*2].mac,max(t[i*2+1].mac,t[i*2+1].maxn-t[i*2].minn)); t[i].mic=max(t[i*2].mic,max(t[i*2+1].mic,t[i*2].maxn-t[i*2+1].minn)); t[i].maxn=max(t[i*2].maxn,t[i*2+1].maxn); t[i].minn=min(t[i*2].minn,t[i*2+1].minn); } void build(int i,int l,int r) { int mid; if (l==r) { t[i].maxn=t[i].minn=fy[id[l]];t[i].mac=t[i].mic=0;return; } mid=(l+r)/2; build(i*2,l,mid);build(i*2+1,mid+1,r); updata(i); } void tch(int i,int l,int r,int x,int y) { int mid; if (l==r) { t[i].maxn=t[i].minn=y;t[i].mac=t[i].mic=0;return; } mid=(l+r)/2; if (x<=mid) tch(i*2,l,mid,x,y); else tch(i*2+1,mid+1,r,x,y); updata(i); } struct use task(int i,int l,int r,int ll,int rr) { int mid; struct use n1,n2,ans; bool u1=false,u2=false; if (ll<=l&&r<=rr) return t[i]; mid=(l+r)/2; if (ll<=mid) {u1=true;n1=task(i*2,l,mid,ll,rr);} if (rr>mid) {u2=true;n2=task(i*2+1,mid+1,r,ll,rr);} ans.maxn=0;ans.minn=inf;ans.mac=ans.mic=0; if (u1) { ans.maxn=max(ans.maxn,n1.maxn); ans.minn=min(ans.minn,n1.minn); ans.mac=max(ans.mac,n1.mac); ans.mic=max(ans.mic,n1.mic); } if (u2) { ans.maxn=max(ans.maxn,n2.maxn); ans.minn=min(ans.minn,n2.minn); ans.mac=max(ans.mac,n2.mac); ans.mic=max(ans.mic,n2.mic); } if (u1&&u2) { ans.mac=max(ans.mac,n2.maxn-n1.minn); ans.mic=max(ans.mic,n1.maxn-n2.minn); } return ans; } struct lp{ int fa[maxnode],dep[maxnode],top[maxnode],tid[maxnode],son[maxnode],siz[maxnode]; bool visit[maxnode]; void add(int u,int v) { ++tot;next[tot]=point[u];point[u]=tot;en[tot]=v; ++tot;next[tot]=point[v];point[v]=tot;en[tot]=u; } void dfs1(int u,int ff,int depth) { int i,j,maxsiz=0; fa[u]=ff;dep[u]=depth;visit[u]=true; son[u]=0;siz[u]=1; for (i=point[u];i;i=next[i]) { if (!visit[j=en[i]]) { dfs1(j,u,depth+1); siz[u]+=siz[j]; if (siz[j]>maxsiz) { maxsiz=siz[j];son[u]=j; } } } } void dfs2(int u,int anc) { int i,j; top[u]=anc;tid[u]=++tot; id[tot]=u;visit[u]=false; if (son[u]) dfs2(son[u],anc); for (i=point[u];i;i=next[i]) if (visit[j=en[i]]) dfs2(j,j); } int ask(int a,int b) { int j,ans=0,kk=0; struct use mo[2],i; mo[0].maxn=mo[1].maxn=0;mo[0].minn=mo[1].minn=inf; mo[0].mac=mo[1].mac=mo[0].mic=mo[1].mic=0; while(top[a]!=top[b]) { if (dep[top[a]]<dep[top[b]]) { swap(a,b);kk^=1; } i=task(1,1,tot,tid[top[a]],tid[a]); if (!kk) { ans=max(ans,max(i.mic,i.maxn-mo[kk].minn)); mo[kk].minn=min(mo[kk].minn,i.minn); mo[kk].maxn=max(mo[kk].maxn,i.maxn); } else { ans=max(ans,max(i.mac,mo[kk].maxn-i.minn)); mo[kk].minn=min(mo[kk].minn,i.minn); mo[kk].maxn=max(mo[kk].maxn,i.maxn); } a=fa[top[a]]; } if (dep[a]>dep[b]) { swap(a,b);kk^=1; } i=task(1,1,tot,tid[a],tid[b]); if (!kk) { ans=max(ans,max(i.mac,i.maxn-mo[kk].minn)); mo[kk].maxn=max(mo[kk].maxn,i.maxn); mo[kk].minn=min(mo[kk].minn,i.minn); ans=max(ans,mo[kk^1].maxn-mo[kk].minn); } else { ans=max(ans,max(i.mic,mo[kk].maxn-i.minn)); mo[kk].maxn=max(mo[kk].maxn,i.maxn); mo[kk].minn=min(mo[kk].minn,i.minn); ans=max(ans,mo[kk].maxn-mo[kk^1].minn); } return ans; } }tree; int main() { int n,m,i,j,x,y,u,v; scanf("%d",&n); for (i=1;i<=n;++i) scanf("%d",&fy[i]); for (i=1;i<n;++i) { scanf("%d%d",&u,&v); tree.add(u,v); } memset(tree.visit,false,sizeof(tree.visit)); tree.dfs1(1,0,1);tot=0; tree.dfs2(1,1);scanf("%d",&m); build(1,1,tot); for (i=1;i<=m;++i) { scanf("%d%d",&x,&y); printf("%d\n",tree.ask(x,y)); } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxnode 200001 #define inf 2100000000 using namespace std; int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},fy[maxnode]={0},id[maxnode]={0},tot=0; struct use{ int maxn,minn,mac,mic; }t[maxnode*4]; void updata(int i) { t[i].mac=max(t[i*2].mac,max(t[i*2+1].mac,t[i*2+1].maxn-t[i*2].minn)); t[i].mic=max(t[i*2].mic,max(t[i*2+1].mic,t[i*2].maxn-t[i*2+1].minn)); t[i].maxn=max(t[i*2].maxn,t[i*2+1].maxn); t[i].minn=min(t[i*2].minn,t[i*2+1].minn); } void build(int i,int l,int r) { int mid; if (l==r) { t[i].maxn=t[i].minn=fy[id[l]];t[i].mac=t[i].mic=0;return; } mid=(l+r)/2; build(i*2,l,mid);build(i*2+1,mid+1,r); updata(i); } void tch(int i,int l,int r,int x,int y) { int mid; if (l==r) { t[i].maxn=t[i].minn=y;t[i].mac=t[i].mic=0;return; } mid=(l+r)/2; if (x<=mid) tch(i*2,l,mid,x,y); else tch(i*2+1,mid+1,r,x,y); updata(i); } struct use task(int i,int l,int r,int ll,int rr) { int mid; struct use n1,n2,ans; bool u1=false,u2=false; if (ll<=l&&r<=rr) return t[i]; mid=(l+r)/2; if (ll<=mid) {u1=true;n1=task(i*2,l,mid,ll,rr);} if (rr>mid) {u2=true;n2=task(i*2+1,mid+1,r,ll,rr);} ans.maxn=0;ans.minn=inf;ans.mac=ans.mic=0; if (u1) { ans.maxn=max(ans.maxn,n1.maxn); ans.minn=min(ans.minn,n1.minn); ans.mac=max(ans.mac,n1.mac); ans.mic=max(ans.mic,n1.mic); } if (u2) { ans.maxn=max(ans.maxn,n2.maxn); ans.minn=min(ans.minn,n2.minn); ans.mac=max(ans.mac,n2.mac); ans.mic=max(ans.mic,n2.mic); } if (u1&&u2) { ans.mac=max(ans.mac,n2.maxn-n1.minn); ans.mic=max(ans.mic,n1.maxn-n2.minn); } return ans; } struct lp{ int fa[maxnode],dep[maxnode],top[maxnode],tid[maxnode],son[maxnode],siz[maxnode]; bool visit[maxnode]; void add(int u,int v) { ++tot;next[tot]=point[u];point[u]=tot;en[tot]=v; ++tot;next[tot]=point[v];point[v]=tot;en[tot]=u; } void dfs1(int u,int ff,int depth) { int i,j,maxsiz=0; fa[u]=ff;dep[u]=depth;visit[u]=true; son[u]=0;siz[u]=1; for (i=point[u];i;i=next[i]) { if (!visit[j=en[i]]) { dfs1(j,u,depth+1); siz[u]+=siz[j]; if (siz[j]>maxsiz) { maxsiz=siz[j];son[u]=j; } } } } void dfs2(int u,int anc) { int i,j; top[u]=anc;tid[u]=++tot; id[tot]=u;visit[u]=false; if (son[u]) dfs2(son[u],anc); for (i=point[u];i;i=next[i]) if (visit[j=en[i]]) dfs2(j,j); } int ask(int a,int b) { int j,ans=0,kk=0; struct use mo[2],i; mo[0].maxn=mo[1].maxn=0;mo[0].minn=mo[1].minn=inf; mo[0].mac=mo[1].mac=mo[0].mic=mo[1].mic=0; while(top[a]!=top[b]) { if (dep[top[a]]<dep[top[b]]) { swap(a,b);kk^=1; } i=task(1,1,tot,tid[top[a]],tid[a]); if (!kk) { ans=max(ans,max(i.mic,i.maxn-mo[kk].minn)); mo[kk].minn=min(mo[kk].minn,i.minn); mo[kk].maxn=max(mo[kk].maxn,i.maxn); } else { ans=max(ans,max(i.mac,mo[kk].maxn-i.minn)); mo[kk].minn=min(mo[kk].minn,i.minn); mo[kk].maxn=max(mo[kk].maxn,i.maxn); } a=fa[top[a]]; } if (dep[a]>dep[b]) { swap(a,b);kk^=1; } i=task(1,1,tot,tid[a],tid[b]); if (!kk) { ans=max(ans,max(i.mac,i.maxn-mo[kk].minn)); mo[kk].maxn=max(mo[kk].maxn,i.maxn); mo[kk].minn=min(mo[kk].minn,i.minn); ans=max(ans,mo[kk^1].maxn-mo[kk].minn); } else { ans=max(ans,max(i.mic,mo[kk].maxn-i.minn)); mo[kk].maxn=max(mo[kk].maxn,i.maxn); mo[kk].minn=min(mo[kk].minn,i.minn); ans=max(ans,mo[kk].maxn-mo[kk^1].minn); } return ans; } }tree; int main() { int n,m,i,j,x,y,u,v; scanf("%d",&n); for (i=1;i<=n;++i) scanf("%d",&fy[i]); for (i=1;i<n;++i) { scanf("%d%d",&u,&v); tree.add(u,v); } memset(tree.visit,false,sizeof(tree.visit)); tree.dfs1(1,0,1);tot=0; tree.dfs2(1,1);scanf("%d",&m); build(1,1,tot); for (i=1;i<=m;++i) { scanf("%d%d%d",&j,&x,&y); if (j==0) tch(1,1,tot,tree.tid[x],y); else printf("%d\n",tree.ask(x,y)); } }
moe
题目大意:给定一个图,有两种操作:1)删掉一条边;2)求图中桥的数量。
思路:对于删边类的问题,大多是倒着来做。删掉所有边后,可能仍然是个图,我们dfs出一棵树,这些边都是当前的桥,把图中的边一条一条加上,它连接的两点间的边都不是桥了,维护的过程就是链剖+线段树区间修改和查询。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #define maxnode 100005 using namespace std; struct use{ int st,en,flag; }edge[maxnode]={0}; struct uu{ int num,delta; }t[maxnode*4]={0}; int tot=0,ask[maxnode][4]={0},point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},n,tot1=0; bool visit[maxnode]={false}; map <int,int> dui[maxnode]; void add(int u,int v) { edge[++tot].st=u;edge[tot].en=v;edge[tot].flag=0; dui[u][v]=dui[v][u]=tot; next[tot*2-1]=point[u];point[u]=tot*2-1;en[tot*2-1]=v; next[tot*2]=point[v];point[v]=tot*2;en[tot*2]=u; } void updata(int i){t[i].num=t[i*2].num+t[i*2+1].num;} void pushdown(int i,int l,int r) { int mid; if (t[i].delta) { t[i*2].delta=t[i*2+1].delta=1; t[i*2].num=t[i*2+1].num=0; t[i].delta=0; } } void build(int i,int l,int r) { int mid; if (l==r){t[i].num=1;t[i].delta=0;return;} mid=(l+r)/2;build(i*2,l,mid);build(i*2+1,mid+1,r); updata(i); } int task(int i,int l,int r,int ll,int rr) { int mid,ans=0; if (ll<=l&&r<=rr) return t[i].num; mid=(l+r)/2;pushdown(i,l,r); if (ll<=mid) ans+=task(i*2,l,mid,ll,rr); if (rr>mid) ans+=task(i*2+1,mid+1,r,ll,rr); return ans; } void tch(int i,int l,int r,int ll,int rr) { int mid; if (ll<=l&&r<=rr) { t[i].num=0;t[i].delta=1;return; } mid=(l+r)/2;pushdown(i,l,r); if (ll<=mid) tch(i*2,l,mid,ll,rr); if (rr>mid) tch(i*2+1,mid+1,r,ll,rr); updata(i); } struct lp{ int fa[maxnode],tid[maxnode],son[maxnode],siz[maxnode],top[maxnode],dep[maxnode]; void dfs1(int u,int faa,int depth) { int maxsiz=0,i,j; fa[u]=faa;dep[u]=depth; son[u]=0;siz[u]=1;visit[u]=true; for (i=point[u];i;i=next[i]) if (edge[(i+1)/2].flag==0&&!visit[en[i]]) { edge[(i+1)/2].flag=1; dfs1(en[i],u,depth+1);siz[u]+=siz[en[i]]; if (siz[en[i]]>maxsiz) { son[u]=en[i];maxsiz=siz[en[i]]; } } } void dfs2(int u,int anc) { int i,j; tid[u]=++tot1;top[u]=anc;visit[u]=false; if (son[u]) dfs2(son[u],anc); for (i=point[u];i;i=next[i]) if (edge[(i+1)/2].flag==1&&visit[en[i]]) dfs2(en[i],en[i]); } void change(int a,int b) { while(top[a]!=top[b]) { if (dep[top[a]]<dep[top[b]]) swap(a,b); tch(1,1,n,tid[top[a]],tid[a]); a=fa[top[a]]; } if (dep[a]>dep[b]) swap(a,b); if (a!=b) tch(1,1,n,tid[son[a]],tid[b]); } int query(int a,int b) { int ans=0; while(top[a]!=top[b]) { if (dep[top[a]]<dep[top[b]]) swap(a,b); ans+=task(1,1,n,tid[top[a]],tid[a]); a=fa[top[a]]; } if (dep[a]>dep[b]) swap(a,b); if (a!=b) ans+=task(1,1,n,tid[son[a]],tid[b]); return ans; } }tree; int main() { freopen("moe.in","r",stdin); freopen("moe.out","w",stdout); int m,i,j,c,a,b,tt=0; scanf("%d%d",&n,&m); for (i=1;i<=m;++i){scanf("%d%d",&a,&b);add(a,b);} while(scanf("%d",&c)==1) { if (c==-1) break; scanf("%d%d",&a,&b); ask[++tt][0]=c;ask[tt][1]=a;ask[tt][2]=b; if (!c) edge[dui[a][b]].flag=-1; } tree.dfs1(1,0,1);tree.dfs2(1,1);build(1,1,n); for (i=1;i<=tot;++i) if (edge[i].flag==0) tree.change(edge[i].st,edge[i].en); for (i=tt;i>=1;--i) { if (ask[i][0]==0) tree.change(ask[i][1],ask[i][2]); else ask[i][3]=tree.query(ask[i][1],ask[i][2]); } for (i=1;i<=tt;++i) if (ask[i][0]) printf("%d\n",ask[i][3]); fclose(stdin); fclose(stdout); }
sdoi2014 旅行
题目大意:给定一棵树和树上节点的颜色和权值,求两点路径上的某种颜色的权值和和权值最大值。
思路:树链剖分+动态开点线段树。对每种颜色建线段树,然后更新就可以了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxm 100005 #define inf 2100000000 using namespace std; struct use{ int ls,rs,l,r,maxn,sum; }t[maxm*100]={0}; int wi[maxm]={0},ci[maxm]={0},point[maxm]={0},en[maxm*2]={0},next[maxm*2]={0},tot=0,n,sum=0, id[maxm]={0},root[maxm]={0}; char ss[10]; void add(int u,int v){ next[++tot]=point[u];point[u]=tot;en[tot]=v; next[++tot]=point[v];point[v]=tot;en[tot]=u; } void updata(int i){ t[i].maxn=max(t[t[i].ls].maxn,t[t[i].rs].maxn); t[i].sum=t[t[i].ls].sum+t[t[i].rs].sum; } void tins(int &i,int l,int r,int x,int w,int kk){ if (!i){t[i=++sum].l=l;t[i].r=r;t[i].maxn=-inf;} if (l==r){ if (kk>0) t[i].maxn=t[i].sum=w; else{t[i].maxn=-inf;t[i].sum=0;} return; }int mid=(l+r)/2; if (x<=mid) tins(t[i].ls,l,mid,x,w,kk); else tins(t[i].rs,mid+1,r,x,w,kk); updata(i); } int tsum(int i,int l,int r,int ll,int rr){ int mid,ans=0;if (!i) return 0; if (ll<=l&&r<=rr) return t[i].sum; mid=(l+r)/2; if (ll<=mid) ans+=tsum(t[i].ls,l,mid,ll,rr); if (rr>mid) ans+=tsum(t[i].rs,mid+1,r,ll,rr); return ans; } int tmax(int i,int l,int r,int ll,int rr){ int mid,ans;ans=-inf; if (!i) return -inf; if (ll<=l&&r<=rr) return t[i].maxn; mid=(l+r)/2; if (ll<=mid) ans=max(ans,tmax(t[i].ls,l,mid,ll,rr)); if (rr>mid) ans=max(ans,tmax(t[i].rs,mid+1,r,ll,rr)); return ans; } struct lp{ int fa[maxm],dep[maxm],tid[maxm],top[maxm],son[maxm],siz[maxm]; bool visit[maxm]; void dfs1(int u,int faa,int de){ int i,j,maxsiz=0;fa[u]=faa;dep[u]=de; son[u]=0;siz[u]=1;visit[u]=false; for (i=point[u];i;i=next[i]) if ((j=en[i])!=faa){ dfs1(j,u,de+1);siz[u]+=siz[j]; if (siz[j]>maxsiz){maxsiz=siz[j];son[u]=j;} } } void dfs2(int u,int anc){ int i,j;top[u]=anc;visit[u]=true; tid[u]=++tot;id[tot]=u; if (son[u]) dfs2(son[u],anc); for (i=point[u];i;i=next[i]) if (!visit[j=en[i]]) dfs2(j,j); } int qsum(int a,int b){ int ans=0,co;co=ci[a]; while(top[a]!=top[b]){ if (dep[top[a]]<dep[top[b]]) swap(a,b); ans+=tsum(root[co],1,n,tid[top[a]],tid[a]); a=fa[top[a]]; }if (dep[a]>dep[b]) swap(a,b); ans+=tsum(root[co],1,n,tid[a],tid[b]); return ans; } int qmax(int a,int b){ int ans=-inf;int co=ci[a]; while(top[a]!=top[b]){ if (dep[top[a]]<dep[top[b]]) swap(a,b); ans=max(ans,tmax(root[co],1,n,tid[top[a]],tid[a])); a=fa[top[a]]; }if (dep[a]>dep[b]) swap(a,b); ans=max(ans,tmax(root[co],1,n,tid[a],tid[b])); return ans; } }tree; int main() { int q,i,j,u,v;scanf("%d%d",&n,&q); for (i=1;i<=n;++i) scanf("%d%d",&wi[i],&ci[i]); for (i=1;i<n;++i){scanf("%d%d",&u,&v);add(u,v);} tree.dfs1(1,0,1);tot=0;tree.dfs2(1,1); t[0].maxn=-inf;t[0].sum=0; for (i=1;i<=n;++i) tins(root[ci[i]],1,n,tree.tid[i],wi[i],1); for (i=1;i<=q;++i){ scanf("%s",&ss);scanf("%d%d",&u,&v); if (ss[0]=='C'){ if (ss[1]=='C'){ tins(root[ci[u]],1,n,tree.tid[u],wi[u],-1); tins(root[ci[u]=v],1,n,tree.tid[u],wi[u],1); } else tins(root[ci[u]],1,n,tree.tid[u],wi[u]=v,1); }else{ if (ss[1]=='S') printf("%d\n",tree.qsum(u,v)); else printf("%d\n",tree.qmax(u,v)); } } }
bzoj4336 骑士的旅行
题目大意:给定一棵树,有m个骑士在这棵树上,查询一条链上前k个骑士的武力值,修改:1)一个骑士换一个点;2)骑士换一个武力值。
思路:树链剖分+线段树+map。因为k很小,所以可以在线段树里维护出前k大的。用map记录一下每个点上的骑士的信息,用线段树维护,树链剖分查询就可以了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #define maxm 40005 #define maxx 80005 using namespace std; map<int,int> cnt[maxm]; int n,k,point[maxm]={0},en[maxx]={0},next[maxx]={0},tot=0,ti=0,id[maxm]={0}; bool visit[maxm]={false}; struct use{ int ki[21]; void init(){ki[0]=0;} }t[maxm*4]; inline int sc(){ char ch=getchar();int x=0; while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9'){ x=x*10+ch-'0';ch=getchar(); }return x; } struct uu{int po,v;}qi[maxm]; inline void add(int u,int v){ next[++tot]=point[u];point[u]=tot;en[tot]=v; next[++tot]=point[v];point[v]=tot;en[tot]=u; } inline void in(int i,int x){ int tt;t[i].init(); if (!cnt[x].size()) return; map<int,int>::iterator it; for (it=cnt[x].end(),--it;;--it){ for (tt=min(it->second,k-t[i].ki[0]);tt;--tt) t[i].ki[++t[i].ki[0]]=it->first; if (t[i].ki[0]==k||it==cnt[x].begin()) break; } } inline use updata(use x,use y){ use cc;cc.init(); int i=1,j=1; while(i<=x.ki[0]&&j<=y.ki[0]&&cc.ki[0]<k){ if (x.ki[i]>=y.ki[j]) cc.ki[++cc.ki[0]]=x.ki[i++]; else cc.ki[++cc.ki[0]]=y.ki[j++]; }if (cc.ki[0]<k){ if (i<=x.ki[0]) for (;i<=x.ki[0]&&cc.ki[0]<k;++i) cc.ki[++cc.ki[0]]=x.ki[i]; else for (;j<=y.ki[0]&&cc.ki[0]<k;++j) cc.ki[++cc.ki[0]]=y.ki[j]; }return cc; } inline void build(int i,int l,int r){ if (l==r){in(i,id[l]);return;} int mid=(l+r)>>1; build(i<<1,l,mid);build(i<<1|1,mid+1,r); t[i]=updata(t[i<<1],t[i<<1|1]); } inline void tch(int i,int l,int r,int x){ if (l==r){in(i,id[l]);return;} int mid=(l+r)>>1; if (x<=mid) tch(i<<1,l,mid,x); else tch(i<<1|1,mid+1,r,x); t[i]=updata(t[i<<1],t[i<<1|1]); } inline use task(int i,int l,int r,int ll,int rr){ use cc;cc.init(); if (ll<=l&&r<=rr) return t[i]; int mid=(l+r)>>1; if (ll<=mid) cc=updata(cc,task(i<<1,l,mid,ll,rr)); if (rr>mid) cc=updata(cc,task(i<<1|1,mid+1,r,ll,rr)); return cc; } struct lp{ int fa[maxm],dep[maxm],tid[maxm],top[maxm],son[maxm],siz[maxm]; inline void dfs1(int u,int ff,int de){ int i,v,maxsiz=0;dep[u]=de; siz[u]=1;son[u]=0;fa[u]=ff; for (i=point[u];i;i=next[i]){ if ((v=en[i])==ff) continue; dfs1(v,u,de+1);siz[u]+=siz[v]; if (siz[v]>maxsiz){maxsiz=siz[v];son[u]=v;} } } inline void dfs2(int u,int anc){ int i,v;top[u]=anc;visit[u]=true; tid[u]=++ti;id[ti]=u; if (son[u]) dfs2(son[u],anc); for (i=point[u];i;i=next[i]){ if (visit[v=en[i]]) continue; dfs2(v,v); } } inline use ask(int x,int y){ use cc;cc.init(); while(top[x]!=top[y]){ if (dep[top[x]]<dep[top[y]]) swap(x,y); cc=updata(cc,task(1,1,n,tid[top[x]],tid[x])); x=fa[top[x]]; }if (dep[x]>dep[y]) swap(x,y); cc=updata(cc,task(1,1,n,tid[x],tid[y])); return cc; } }tree; int main(){ int m,i,j,u,v,q,ti,xi,yi; use ci;n=sc(); for (i=1;i<n;++i){u=sc();v=sc();add(u,v);} tree.dfs1(1,0,1);tree.dfs2(1,1);m=sc(); for (i=1;i<=m;++i){ qi[i].v=sc();qi[i].po=sc(); ++cnt[qi[i].po][qi[i].v]; }q=sc();k=sc();build(1,1,n); for (i=1;i<=q;++i){ ti=sc();xi=sc();yi=sc(); if (ti==1){ ci=tree.ask(xi,yi); if (!ci.ki[0]) printf("-1\n"); else{ for (j=1;j<=ci.ki[0];++j) printf("%d ",ci.ki[j]); printf("\n"); } }if (ti==2){ --cnt[qi[xi].po][qi[xi].v];tch(1,1,n,tree.tid[qi[xi].po]); ++cnt[qi[xi].po=yi][qi[xi].v];tch(1,1,n,tree.tid[qi[xi].po]); }if (ti==3){ --cnt[qi[xi].po][qi[xi].v]; ++cnt[qi[xi].po][qi[xi].v=yi]; tch(1,1,n,tree.tid[qi[xi].po]); } } }
bzoj3626 LCA
题目大意:给定一棵树,每个询问是求sigma(i=l~r)dep(lca(i,z))。
思路:容斥+树链剖分。答案显然是1~l-1的和-1~r的和,所以要求1~i与z的lca的深度和。离线操作,把所有的l、r排序,把1~n依次加入树中,所以就是求树中有的点和z的lca的dep和,因为lca的dep和就是z到根的路径上,每个点的不在这条链上的孩子的个数乘这个点的dep,这个可以用链剖来求,建两棵线段树:一棵维护树上那些点标记,一棵维护这一段区间对应点的答案(这个答案是这个点的子树中不再这个点所在重链的点的个数*dep),查询的时候要在轻重链的地方式子算一下,插入的时候插给这个点到1的路径上所有轻重链交替的点就可以了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxm 50005 #define maxe 100005 #define p 201314 #define LL long long using namespace std; struct use{ int x,z,po; bool operator<(const use&xx)const{ return x==xx.x ? z<xx.z : x<xx.x; } }li[maxm],ri[maxm],lr[maxe]; int point[maxm]={0},next[maxm]={0},en[maxm]={0},tot=0,id[maxm],ti=0,n,la[maxm]={0}, tree[maxm*4]={0},fa[maxm],tid[maxm],top[maxm],son[maxm]; LL t[maxm*4]={0LL},sizb[maxm]={0LL},siz[maxm],dep[maxm],ans[maxm]={0LL}; bool visit[maxm]={false}; void add(int u,int v){next[++tot]=point[u];point[u]=tot;en[tot]=v;} LL task(int i,int l,int r,int ll,int rr){ if (ll<=l&&r<=rr) return t[i]; int mid=l+r>>1;LL ans=0LL; if (ll<=mid) ans+=task(i<<1,l,mid,ll,rr); if (rr>mid) ans+=task(i<<1|1,mid+1,r,ll,rr); return ans; } void tch(int i,int l,int r,int x){ if (l==r){t[i]=dep[id[l]]*sizb[id[l]]%p;return;} int mid=l+r>>1; if (x<=mid) tch(i<<1,l,mid,x); else tch(i<<1|1,mid+1,r,x); t[i]=(t[i<<1]+t[i<<1|1])%p; } void change(int i,int l,int r,int x){ if (l==r){tree[i]=1;return;} int mid=l+r>>1; if (x<=mid) change(i<<1,l,mid,x); else change(i<<1|1,mid+1,r,x); tree[i]=tree[i<<1]+tree[i<<1|1]; } int asum(int i,int l,int r,int ll,int rr){ if (ll<=l&&r<=rr) return tree[i]; int mid=l+r>>1;int sum=0; if (ll<=mid) sum+=asum(i<<1,l,mid,ll,rr); if (rr>mid) sum+=asum(i<<1|1,mid+1,r,ll,rr); return sum; } struct lp{ void dfs1(int u,int ff,int de){ int i,j,v;LL mas=0; dep[u]=de;fa[u]=ff; son[u]=0;siz[u]=1LL; for (i=point[u];i;i=next[i]){ if ((v=en[i])==ff) continue; dfs1(v,u,de+1);siz[u]+=siz[v]; if (siz[v]>mas){mas=siz[v];son[u]=v;} } } void dfs2(int u,int anc){ int i,j,v;top[u]=anc; id[tid[u]=++ti]=u;visit[u]=true; if (son[u]) dfs2(son[u],anc); for (i=point[u];i;i=next[i]){ if (visit[v=en[i]]) continue; dfs2(v,v); }la[u]=ti; } void cha(int a,int b){ change(1,1,n,tid[b]); while(top[a]!=top[b]){ if (dep[top[a]]<dep[top[b]]) swap(a,b); ++sizb[a];tch(1,1,n,tid[a]); a=fa[top[a]]; }if (dep[a]>dep[b]) swap(a,b); ++sizb[b];tch(1,1,n,tid[b]); } LL ask(int a,int b){ LL ans=0LL; if (son[b]) ans=(ans+dep[b]*asum(1,1,n,tid[son[b]],la[son[b]])%p)%p; while(top[a]!=top[b]){ if (dep[top[a]]<dep[top[b]]) swap(a,b); ans=(ans+task(1,1,n,tid[top[a]],tid[a]))%p; ans=((ans-dep[fa[top[a]]]*asum(1,1,n,tid[top[a]],la[top[a]])%p)%p+p)%p; a=fa[top[a]]; if (son[a]) ans=(ans+dep[a]*asum(1,1,n,tid[son[a]],la[son[a]])%p)%p; }if (dep[a]>dep[b]) swap(a,b); ans=(ans+task(1,1,n,tid[a],tid[b]))%p; return ans; } }tr; int main(){ int q,i,j,l,r,z;LL ci;scanf("%d%d",&n,&q); for (i=1;i<n;++i){scanf("%d",&j);add(j+1,i+1);} for (tot=0,i=1;i<=q;++i){ scanf("%d%d%d",&li[i].x,&ri[i].x,&z); ++ri[i].x;li[i].z=ri[i].z=++z; li[i].po=ri[i].po=i; if (li[i].x) lr[++tot]=li[i]; if (ri[i].x) lr[++tot]=ri[i]; }tr.dfs1(1,0,1);tr.dfs2(1,1); sort(lr+1,lr+tot+1); for (l=i=1;i<=tot;){ j=i;while(j<tot&&lr[j+1].x==lr[i].x) ++j; while(l<=lr[j].x) tr.cha(1,l++); for (;i<=j;++i){ ci=tr.ask(1,lr[i].z);z=lr[i].po; if (lr[i].x==ri[z].x) ans[z]=(ans[z]+ci)%p; if (lr[i].x==li[z].x) ans[z]=((ans[z]-ci)%p+p)%p; } }for (i=1;i<=q;++i) printf("%I64d\n",ans[i]); }
还有一种更简单的方法:离线处理,每次插入的时候就是把这个点到根上所有点的权值+1,查询的时候就是这个点到根的链的权值和。(因为这里求的是深度之和,所以每个点lca以上的所有点都要加给答案)