[LNOI2014]LCA
这道题难道不是数据结构水题吗 逃)
首先想到一个i点的\(dep\)相当于根节点走到i 进过的点之和,所以这个点对答案的贡献就是从这个点走到根节点。因此我们可以转换为当前节点\(i\)到根节点所经过的所有节点权值++。
显然可以用线段树+树链剖分的数据结构进行优化 对于每一个询问 建一颗权值线段树 存储当前区间\(sum\),\(sum\)存储的就是\(sum\)
然后我们需要想到用 类似于前缀和的思想来进行优化
例如 \(l=2 ,r=4 ,z=4\) 我们可以用前缀和的思想进行优化 计算\(1到4\)的\(sum\)\(-1到1的sum\) 就可以得到答案了
想到了前缀和 想到了树剖+线段树 如果每一次查询 你都要新建两次树
那就会GG!
因此我们又想到了莫队的思想,将询问区间的\(l,r\)排序(因为询问区间为\(1到l\),\(1到r\),左区间都是一样的,所以我们可以将l,r一起排序),然后一个一个的加点 这样就可以不用每一次询问都新建一颗树了
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define int long long using namespace std; const int mod=201314,maxn=100010; int n,q,tot,fa[maxn],cnt_q; int first[maxn],nxt[maxn<<1],to[maxn<<1],dep[maxn<<1],cnt_id; int id[maxn<<1],rk[maxn<<1],size[maxn<<1],son[maxn<<1],top[maxn<<1],now; int tag[maxn<<1],sum[maxn<<1]; struct node{ int id,pos,z,flag; inline bool operator <(const node &x)const{ return pos<x.pos || (x.pos==pos && id<x.id); } }ques[maxn<<4]; struct node1{ int ans1,ans2; }ans[maxn<<2]; void dfs1(int x,int father){ size[x]=1;fa[x]=father; for(int i=first[x];i;i=nxt[i]){ int y=to[i];if(y==father) continue; dep[y]=dep[x]+1; dfs1(y,x);size[x]+=size[y]; if(size[son[x]]<size[y]) son[x]=y; } } void dfs2(int x,int topo){ id[x]=++cnt_id;rk[cnt_id]=x;top[x]=topo; if(son[x]) dfs2(son[x],topo); for(int i=first[x];i;i=nxt[i]){ int y=to[i];if(y==fa[y] || y==son[x]) continue; dfs2(y,y); } } void add(int x,int y){nxt[++tot]=first[x];first[x]=tot;to[tot]=y;} void tagg(int node,int l,int r,int ta) { sum[node]=(sum[node]+(r-l+1)*ta)%mod; if(l<r) tag[node]=(tag[node]+ta)%mod; } void push_down(int node,int l,int r){ if(l<r && tag[node]){ int mid=(l+r)>>1; tagg(node<<1,l,mid,tag[node]); tagg(node<<1|1,mid+1,r,tag[node]); } tag[node]=0; } void push_up(int node){sum[node]=(sum[node<<1]+sum[node<<1|1])%mod;} void modify(int node,int l,int r,int ql,int qr){ if(qr<l || ql>r) return ; if(ql<=l && r<=qr){ tagg(node,l,r,1); return ; } push_down(node,l,r); int mid=(l+r)>>1; modify(node<<1,l,mid,ql,qr);modify(node<<1|1,mid+1,r,ql,qr); push_up(node); } void line_modify(int x,int y){ int tx=top[x],ty=top[y]; while(tx!=ty){ if(dep[tx]<dep[ty]){ x^=y^=x^=y;tx^=ty^=tx^=ty; } modify(1,1,n,id[tx],id[x]); x=fa[tx];tx=top[x]; } if(dep[x]<dep[y]) x^=y^=x^=y; modify(1,1,n,id[y],id[x]); } int query(int node,int l,int r,int ql,int qr){ if(ql<=l && r<=qr) return (sum[node]%mod); push_down(node,l,r); int mid=(l+r)>>1,anss=0; if(ql<=mid) anss+=query(node<<1,l,mid,ql,qr); if(mid<qr) anss+=query(node<<1|1,mid+1,r,ql,qr); return anss%mod; } int line_query(int x,int y){ int tx=top[x],ty=top[y],anss=0; while(tx!=ty){ if(dep[tx]<dep[ty]){ x^=y^=x^=y;tx^=ty^=tx^=ty; } anss+=query(1,1,n,id[tx],id[x]); anss%=mod; x=fa[tx];tx=top[x]; } if(dep[x]<dep[y]) x^=y^=x^=y; anss+=query(1,1,n,id[y],id[x]); return anss%mod; } signed main(){ scanf("%lld %lld",&n,&q); for(int i=2,x;i<=n;i++){ scanf("%lld",&x);add(++x,i); } dep[1]=1; dfs1(1,0);dfs2(1,1); for(int i=1,l,r,z;i<=q;i++){ scanf("%lld %lld %lld",&l,&r,&z);r++;z++; ques[++cnt_q]=((node){i,l,z,0});ques[++cnt_q]=((node){i,r,z,1}); } sort(ques+1,ques+1+cnt_q);now=0; for(int i=1;i<=cnt_q;i++){ while(now<ques[i].pos) line_modify(1,++now); int num=ques[i].id; if(ques[i].flag==1) ans[num].ans1=line_query(1,ques[i].z); else ans[num].ans2 =line_query(1,ques[i].z); } for(int i=1;i<=q;i++) printf("%lld\n",(ans[i].ans1-ans[i].ans2+mod)%mod); return 0; }