BZOJ3626 神思路的树链剖分+线段树维护
给清华爷的思路跪了 想了N久 觉得可以深度建树开二维的来维护标记...然而N->50000数组存不下 看了别人的题解....原来可以用线段树离线操作对于这个点的深度贡献对于经过的每个节点+1 类似于前缀和的操作 然后对于操作离散化(嗯 最关键的操作就是把深度贡献 均分给他经过的节点上....至于为什么 可以手动画一画 然后想明白这个就发现只是树剖的基本操作 进行区间更新和区间查询即可
3626: [LNOI2014]LCA
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3482 Solved: 1365
[Submit][Status][Discuss]
Description
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。
(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)
Input
第一行2个整数n q。
接下来n-1行,分别表示点1到点n-1的父节点编号。
接下来q行,每行3个整数l r z。
Output
输出q行,每行表示一个询问的答案。每个答案对201314取模输出
Sample Input
5 2
0
0
1
1
1 4 3
1 4 2
0
0
1
1
1 4 3
1 4 2
Sample Output
8
5
5
/************************************************************** Problem: 3626 User: wang9897 Language: C++ Result: Accepted Time:2288 ms Memory:8776 kb ****************************************************************/ #include <bits/stdc++.h> #define N 50005 #define lth 201314 using namespace std; int son[N],num[N],fa[N],dep[N]; int p[N],fp[N],tp[N],cnt,n,q; vector<int>vec[N]; int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f*x; } void dfs1(int v,int pre,int deep){ num[v]=1;fa[v]=pre;dep[v]=deep+1; for(int i=0;i<vec[v].size();i++){ if(vec[v][i]!=pre){ dfs1(vec[v][i],v,deep+1); num[v]+=num[vec[v][i]]; if(son[v]==-1||num[vec[v][i]]>num[son[v]]){ son[v]=vec[v][i]; } } } } void dfs2(int v,int td){ p[v]=++cnt;fp[cnt]=v;tp[v]=td; if(son[v]!=-1) dfs2(son[v],td); for(int i=0;i<vec[v].size();i++){ if(vec[v][i]!=fa[v]&&vec[v][i]!=son[v]) dfs2(vec[v][i],vec[v][i]); } } typedef struct node{ int l,r,sum,flag; }node; node d[N<<2]; void push(int x){ if(d[x].flag){ d[x<<1].sum=(d[x<<1].sum+(1ll*d[x].flag*(d[x<<1].r-d[x<<1].l+1))%lth)%lth;d[x<<1|1].sum=(d[x<<1|1].sum+(1ll*d[x].flag*(d[x<<1|1].r-d[x<<1|1].l+1))%lth)%lth; d[x<<1].flag=(d[x<<1].flag+d[x].flag)%lth;d[x<<1|1].flag=(d[x<<1|1].flag+d[x].flag)%lth; d[x].flag=0; } } void up(int x){ d[x].sum=(d[x<<1].sum+d[x<<1|1].sum)%lth; } void built(int rt,int l,int r){ if(l==r){ d[rt].l=d[rt].r=l;d[rt].flag=d[rt].sum=0; return ; } int mid=(l+r)>>1; built(rt<<1,l,mid); built(rt<<1|1,mid+1,r); d[rt].l=d[rt<<1].l;d[rt].r=d[rt<<1|1].r;d[rt].flag=0; up(rt); } void update(int root,int l,int r){ if(l<=d[root].l&&d[root].r<=r){ d[root].flag+=1;d[root].sum=(d[root].sum+(d[root].r-d[root].l+1)%lth)%lth; return ; } push(root); int mid=(d[root].l+d[root].r)>>1; if(l<=mid) update(root<<1,l,r); if(r>mid) update(root<<1|1,l,r); up(root); } int ans; void querty(int root,int l,int r){ if(l<=d[root].l&&d[root].r<=r){ ans+=d[root].sum; return ; } int mid=(d[root].l+d[root].r)>>1; push(root); if(l<=mid) querty(root<<1,l,r); if(r>mid) querty(root<<1|1,l,r); up(root); } int Sum(int v,int t){ int ans1=0;int vv=tp[v]; while(vv!=1){ if(t==1) update(1,p[vv],p[v]); else{ ans=0;querty(1,p[vv],p[v]); ans1=(ans1+ans)%lth; } v=fa[vv];vv=tp[v]; } if(t==1) update(1,1,p[v]); else{ ans=0;querty(1,1,p[v]); ans1=(ans1+ans)%lth; } return ans1; } typedef struct List{ int l,wei,z; friend bool operator <(List aa,List bb){ return aa.l<bb.l; } }List; List dd[N<<1]; int ans2[N]; int main(){ ios::sync_with_stdio(false); scanf("%d%d",&n,&q);cnt=0; int t; for(int i=1;i<=n;i++) son[i]=-1; for(int i=2;i<=n;i++){ scanf("%d",&t); vec[t+1].push_back(i); } int x,y,z;int cnt1=0; memset(ans2,0,sizeof(ans2)); for(int i=1;i<=q;i++){ scanf("%d %d %d",&x,&y,&z); dd[++cnt1].l=x;dd[cnt1].wei=i;dd[cnt1].z=z+1; dd[++cnt1].l=y+1;dd[cnt1].wei=i;dd[cnt1].z=z+1; } sort(dd+1,dd+cnt1+1); dfs1(1,0,0); // cout<<"sb"<<endl; dfs2(1,1); built(1,1,n);int u=1; for(int i=1;i<=cnt1;i++){ if(dd[i].l==0) continue; while(u<=dd[i].l){ Sum(u,1);u++; } // Sum(u,1); int tt=Sum(dd[i].z,0); //cout<<dd[i].l<<" "<<dd[i].wei<<" "<<tt<<endl; ans2[dd[i].wei]=((tt-ans2[dd[i].wei])%lth+lth)%lth; } for(int i=1;i<=q;i++) printf("%d\n",ans2[i]); return 0; }