隔了俩月,有点看不明白这个模板Σ(っ °Д °;)っ 然后就再看了一遍.....
需要注意的是:
一个节点x所在重链的顶端 即 top[x],与x之间的那条链的所有节点 的dfs序是连续的
所以如果节点x的父亲节点fa与x的dfs序 不连续,则top[x]=x
因为 dfs序是以重链为优先确定的。
所以根据重链可以保证线段树区间的连续性和正确性
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int maxn=2e5+50; vector<int>p[maxn]; int val[maxn],mod; int siz[maxn],dep[maxn],fad[maxn],son[maxn]; int top[maxn],tid[maxn],rnk[maxn],cnt; /* siz[i] 保存以i为根的树的大小 dep[i] i节点的深度 fad[i] i的父亲 son[i] i的重儿子 top[i] 重链的顶端节点 tid[i] i的新编号(dfs) rnk[i] rnk[tid[i]]=i */ inline void dfs1(int u,int fa,int d) { /* u 当前节点 fa 父亲 d 深度 */ dep[u]=d; fad[u]=fa; siz[u]=1; for(int i=0;i<p[u].size();i++) { int v=p[u][i]; if(v==fa)continue; dfs1(v,u,d+1); siz[u]+=siz[v]; if(siz[v]>siz[son[u]])son[u]=v; } } inline void dfs2(int u,int t) { /* u 当前节点 t 顶端重节点 */ top[u]=t; tid[u]=++cnt; rnk[cnt]=u; if(!son[u])return;//当前节点不在重链上 dfs2(son[u],t); for(int i=0;i<p[u].size();i++) { int v=p[u][i]; if(v!=son[u]&&v!=fad[u])dfs2(v,v);//非重节点的top是自己 } } struct kkk{ int l,r;ll sum,la; }tree[maxn<<2]; inline void build(int k,int l,int r) { tree[k].l=l;tree[k].r=r; if(l==r) { tree[k].sum=val[rnk[l]]%mod; return; } int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); tree[k].sum=(tree[k<<1].sum+tree[k<<1|1].sum)%mod; } inline void down(int k) { tree[k<<1].sum=(tree[k<<1].sum+(tree[k<<1].r-tree[k<<1].l+1)*tree[k].la)%mod; tree[k<<1|1].sum=(tree[k<<1|1].sum+(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].la)%mod; tree[k<<1].la=(tree[k<<1].la+tree[k].la)%mod; tree[k<<1|1].la=(tree[k<<1|1].la+tree[k].la)%mod; tree[k].la=0; } inline void add(int k,int l,int r,ll w) { if(l<=tree[k].l&&tree[k].r<=r) { tree[k].la=(tree[k].la+w)%mod; tree[k].sum=(tree[k].sum+(tree[k].r-tree[k].l+1)*w)%mod; return; } if(tree[k].la)down(k); int mid=(tree[k].l+tree[k].r)>>1; if(l<=mid)add(k<<1,l,r,w); if(r>mid)add(k<<1|1,l,r,w); tree[k].sum=(tree[k<<1].sum+tree[k<<1|1].sum)%mod; } inline int query(int k,int l,int r) { if(l<=tree[k].l&&tree[k].r<=r)return tree[k].sum; if(tree[k].la)down(k); int mid=(tree[k].l+tree[k].r)>>1; ll ans=0; if(l<=mid)ans=(ans+query(k<<1,l,r))%mod; if(r>mid)ans=(ans+query(k<<1|1,l,r))%mod; return ans; } inline void addline(int x,int y,ll w) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); add(1,tid[top[x]],tid[x],w); x=fad[top[x]]; } if(dep[x]>dep[y])swap(x,y); add(1,tid[x],tid[y],w); } inline int calline(int x,int y) { ll ans=0; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); ans=(ans+query(1,tid[top[x]],tid[x]))%mod; x=fad[top[x]]; } if(dep[x]>dep[y])swap(x,y); ans=(ans+query(1,tid[x],tid[y]))%mod; return ans; } int main() { int n,m,G,i,u,v,w,op; scanf("%d%d%d%d",&n,&m,&G,&mod); for(i=1;i<=n;i++)scanf("%d",&val[i]); for(i=1;i<n;i++) { scanf("%d%d",&u,&v); p[u].push_back(v); p[v].push_back(u); } // memset(siz,0,sizeof(siz)); memset(son,0,sizeof(son)); dfs1(G,0,1); dfs2(G,G); build(1,1,n); while(m--) { scanf("%d",&op); if(op==1) { scanf("%d%d%d",&u,&v,&w); addline(u,v,w%mod); } else if(op==2) { scanf("%d%d",&u,&v); printf("%d ",calline(u,v)%mod); } else if(op==3) { scanf("%d%d",&u,&w); add(1,tid[u],tid[u]+siz[u]-1,w%mod); } else if(op==4) { scanf("%d",&u); printf("%d ",query(1,tid[u],tid[u]+siz[u]-1)%mod); } } }
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int maxn=2e5+50; vector<int>p[maxn]; int siz[maxn],dep[maxn],fad[maxn],son[maxn]; int top[maxn],tid[maxn],rnk[maxn],cnt; /* siz[i] 保存以i为根的树的大小 dep[i] i节点的深度 fad[i] i的父亲 son[i] i的重儿子 top[i] 重链的顶端节点 tid[i] i的新编号(dfs) rnk[i] rnk[tid[i]]=i */ inline void dfs1(int u,int fa,int d) { /* u 当前节点 fa 父亲 d 深度 */ dep[u]=d; fad[u]=fa; siz[u]=1; for(int i=0;i<p[u].size();i++) { int v=p[u][i]; if(v==fa)continue; dfs1(v,u,d+1); siz[u]+=siz[v]; if(siz[v]>siz[son[u]])son[u]=v; } } inline void dfs2(int u,int t) { /* u 当前节点 t 顶端重节点 */ top[u]=t; tid[u]=++cnt; rnk[cnt]=u; if(!son[u])return;//当前节点不在重链上 dfs2(son[u],t); for(int i=0;i<p[u].size();i++) { int v=p[u][i]; if(v!=son[u]&&v!=fad[u])dfs2(v,v);//非重节点的top是自己 } } struct kkk{ int l,r,sum,la; }tree[maxn<<2]; inline void build(int k,int l,int r) { tree[k].l=l;tree[k].r=r; if(l==r)return; int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } inline void down(int k) { tree[k<<1].sum+=(tree[k<<1].r-tree[k<<1].l+1)*tree[k].la; tree[k<<1|1].sum+=(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].la; tree[k<<1].la+=tree[k].la; tree[k<<1|1].la+=tree[k].la; tree[k].la=0; } inline void add(int k,int l,int r,ll w) { if(l<=tree[k].l&&tree[k].r<=r) { tree[k].la+=w; tree[k].sum+=(tree[k].r-tree[k].l+1)*w; return; } if(tree[k].la)down(k); int mid=(tree[k].l+tree[k].r)>>1; if(l<=mid)add(k<<1,l,r,w); if(r>mid)add(k<<1|1,l,r,w); tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum; } inline int query(int k,int l,int r) { if(l<=tree[k].l&&tree[k].r<=r)return tree[k].sum; if(tree[k].la)down(k); int mid=(tree[k].l+tree[k].r)>>1; int ans=0; if(l<=mid)ans+=query(k<<1,l,r); if(r>mid)ans+=query(k<<1|1,l,r); return ans; } inline void addline(int x,int y,int w) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); add(1,tid[top[x]],tid[x],w); x=fad[top[x]]; } if(dep[x]>dep[y])swap(x,y); add(1,tid[x],tid[y],w); } inline int calline(int x,int y) { int ans=0; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); ans+=query(1,tid[top[x]],tid[x]); x=fad[top[x]]; } if(dep[x]>dep[y])swap(x,y); ans+=query(1,tid[x],tid[y]); return ans; } int main() { int n,q,i,u,v,x,y; scanf("%d%d",&n,&q); for(i=1;i<n;i++) { scanf("%d%d",&u,&v); p[u].push_back(v); p[v].push_back(u); } memset(son,0,sizeof(son)); dfs1(1,0,1); dfs2(1,1); build(1,1,n); while(q--) { scanf("%d%d%d%d",&u,&v,&x,&y); addline(u,v,1); printf("%d ",calline(x,y)); addline(u,v,-1); } }
因为不太会处理边权,所以干脆把边权设成一个点,点权为边权,连接点的点权就为0 。
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int maxn=2e5+50; vector<int>p[maxn]; int val[maxn]; int siz[maxn],dep[maxn],fad[maxn],son[maxn]; int top[maxn],tid[maxn],rnk[maxn],cnt; /* siz[i] 保存以i为根的树的大小 dep[i] i节点的深度 fad[i] i的父亲 son[i] i的重儿子 top[i] 重链的顶端节点 tid[i] i的新编号(dfs) rnk[i] rnk[tid[i]]=i */ inline void dfs1(int u,int fa,int d) { /* u 当前节点 fa 父亲 d 深度 */ dep[u]=d; fad[u]=fa; siz[u]=1; for(int i=0;i<p[u].size();i++) { int v=p[u][i]; if(v==fa)continue; dfs1(v,u,d+1); siz[u]+=siz[v]; if(siz[v]>siz[son[u]])son[u]=v; } } inline void dfs2(int u,int t) { /* u 当前节点 t 顶端重节点 */ top[u]=t; tid[u]=++cnt; rnk[cnt]=u; if(!son[u])return;//当前节点不在重链上 dfs2(son[u],t); for(int i=0;i<p[u].size();i++) { int v=p[u][i]; if(v!=son[u]&&v!=fad[u])dfs2(v,v);//非重节点的top是自己 } } struct kkk{ int l,r,sum,la; }tree[maxn<<2]; inline void build(int k,int l,int r) { tree[k].l=l;tree[k].r=r; if(l==r) { tree[k].sum=val[rnk[l]]; return; } int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); tree[k].sum=tree[k<<1].sum^tree[k<<1|1].sum; } inline int query(int k,int l,int r) { if(l<=tree[k].l&&tree[k].r<=r)return tree[k].sum; int mid=(tree[k].l+tree[k].r)>>1; int ans=0; if(l<=mid)ans^=query(k<<1,l,r); if(r>mid)ans^=query(k<<1|1,l,r); return ans; } inline int calline(int x,int y) { int ans=0; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); ans^=query(1,tid[top[x]],tid[x]); x=fad[top[x]]; } if(dep[x]>dep[y])swap(x,y); ans^=query(1,tid[x],tid[y]); return ans; } int main() { int n,m,i,u,v,w,tot; scanf("%d",&n); tot=n; for(i=1;i<n;i++) { scanf("%d%d%d",&u,&v,&w); p[u].push_back(++tot); p[tot].push_back(u); p[v].push_back(tot); p[tot].push_back(v); val[u]=0;val[v]=0; val[tot]=w; } memset(son,0,sizeof(son)); dfs1(1,0,1); dfs2(1,1); build(1,1,tot); scanf("%d",&m); while(m--) { scanf("%d%d",&u,&v); printf("%d ",calline(u,v)); } }
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int maxn=3e5+50; vector<int>p[maxn]; int siz[maxn],dep[maxn],fad[maxn],son[maxn]; int top[maxn],tid[maxn],rnk[maxn],cnt; /* siz[i] 保存以i为根的树的大小 dep[i] i节点的深度 fad[i] i的父亲 son[i] i的重儿子 top[i] 重链的顶端节点 tid[i] i的新编号(dfs) rnk[i] rnk[tid[i]]=i */ inline void dfs1(int u,int fa,int d) { /* u 当前节点 fa 父亲 d 深度 */ dep[u]=d; fad[u]=fa; siz[u]=1; for(int i=0;i<p[u].size();i++) { int v=p[u][i]; if(v==fa)continue; dfs1(v,u,d+1); siz[u]+=siz[v]; if(siz[v]>siz[son[u]])son[u]=v; } } inline void dfs2(int u,int t) { /* u 当前节点 t 顶端重节点 */ top[u]=t; tid[u]=++cnt; rnk[cnt]=u; if(!son[u])return;//当前节点不在重链上 dfs2(son[u],t); for(int i=0;i<p[u].size();i++) { int v=p[u][i]; if(v!=son[u]&&v!=fad[u])dfs2(v,v);//非重节点的top是自己 } } struct kkk{ int l,r,sum,la; }tree[maxn<<2]; inline void build(int k,int l,int r) { tree[k].l=l;tree[k].r=r; if(l==r)return; int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } inline void down(int k) { tree[k<<1].sum+=(tree[k<<1].r-tree[k<<1].l+1)*tree[k].la; tree[k<<1|1].sum+=(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].la; tree[k<<1].la+=tree[k].la; tree[k<<1|1].la+=tree[k].la; tree[k].la=0; } inline void add(int k,int l,int r,ll w) { if(l<=tree[k].l&&tree[k].r<=r) { tree[k].la+=w; tree[k].sum+=(tree[k].r-tree[k].l+1)*w; return; } if(tree[k].la)down(k); int mid=(tree[k].l+tree[k].r)>>1; if(l<=mid)add(k<<1,l,r,w); if(r>mid)add(k<<1|1,l,r,w); tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum; } inline int query(int k,int l,int r) { if(l<=tree[k].l&&tree[k].r<=r)return tree[k].sum; if(tree[k].la)down(k); int mid=(tree[k].l+tree[k].r)>>1; int ans=0; if(l<=mid)ans+=query(k<<1,l,r); if(r>mid)ans+=query(k<<1|1,l,r); return ans; } inline void addline(int x,int y,int w) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); add(1,tid[top[x]],tid[x],w); x=fad[top[x]]; } if(dep[x]>dep[y])swap(x,y); add(1,tid[x],tid[y],w); } inline int calline(int x,int y) { int ans=0; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); ans+=query(1,tid[top[x]],tid[x]); x=fad[top[x]]; } if(dep[x]>dep[y])swap(x,y); ans+=query(1,tid[x],tid[y]); return ans; } int main() { int n,i,u,v,w,a[maxn],ans; scanf("%d",&n); for(i=1;i<=n;i++)scanf("%d",&a[i]); for(i=1;i<n;i++) { scanf("%d%d",&u,&v); p[u].push_back(v); p[v].push_back(u); } memset(son,0,sizeof(son)); dfs1(1,0,1); dfs2(1,1); build(1,1,n); addline(a[1],a[2],1); for(i=2;i<n;i++) { addline(a[i],a[i+1],1); add(1,tid[a[i]],tid[a[i]],-1); } add(1,tid[a[n]],tid[a[n]],-1); for(i=1;i<=n;i++)printf("%d ",query(1,tid[i],tid[i])); }