BZOJ3626: [LNOI2014]LCA(树链剖分+线段树)
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
解题思路:
蒟蒻QAQ的我一开始以为是树上莫队。
还好吧,这题其实是将Deep重新理解了一下,就是从根到这个点的距离。
我们发现可以在树链上(到1)加一,最后查询到根的权值和。
发现具有区间可减性。
线段树+树剖搞定。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define lll spc<<1 5 #define rrr spc<<1|1 6 typedef long long lnt; 7 const lnt mod=201314; 8 using std::sort; 9 struct trnt{ 10 lnt lzt; 11 lnt val; 12 }tr[1000000]; 13 struct pnt{ 14 int hd; 15 int fa; 16 int tp; 17 int dp; 18 int no; 19 int wgt; 20 int ind; 21 int mxs; 22 }p[1000000]; 23 struct ent{ 24 int twd; 25 int lst; 26 }e[1000000]; 27 int ans[1000000]; 28 struct data{ 29 int no; 30 bool lft; 31 int rgt; 32 int z; 33 }dt[1000000]; 34 int cnt; 35 int dfn; 36 int n,q; 37 bool cmp(data x,data y) 38 { 39 return x.rgt<y.rgt; 40 } 41 void ade(int f,int t) 42 { 43 cnt++; 44 e[cnt].twd=t; 45 e[cnt].lst=p[f].hd; 46 p[f].hd=cnt; 47 return ; 48 } 49 void add(int l,int r,int spc,lnt x) 50 { 51 if(!spc) 52 return ; 53 tr[spc].lzt=(tr[spc].lzt+x)%mod; 54 tr[spc].val=(tr[spc].val+(((lnt)(r-l+1))*x)%mod)%mod; 55 return ; 56 } 57 void pushdown(int spc,int l,int r) 58 { 59 if(tr[spc].lzt) 60 { 61 int mid=(l+r)>>1; 62 add(l,mid,lll,tr[spc].lzt); 63 add(mid+1,r,rrr,tr[spc].lzt); 64 tr[spc].lzt=0; 65 } 66 return ; 67 } 68 void pushup(int spc) 69 { 70 tr[spc].val=(tr[lll].val+tr[rrr].val)%mod; 71 } 72 void update(int l,int r,int ll,int rr,int spc,lnt v) 73 { 74 if(ll>r||l>rr) 75 return ; 76 if(ll<=l&&r<=rr) 77 { 78 add(l,r,spc,v); 79 return ; 80 } 81 pushdown(spc,l,r); 82 int mid=(l+r)>>1; 83 update(l,mid,ll,rr,lll,v); 84 update(mid+1,r,ll,rr,rrr,v); 85 pushup(spc); 86 return ; 87 } 88 lnt query(int l,int r,int ll,int rr,int spc) 89 { 90 if(ll>r||l>rr) 91 return 0ll; 92 if(ll<=l&&r<=rr) 93 return tr[spc].val; 94 int mid=(l+r)>>1; 95 pushdown(spc,l,r); 96 return (query(l,mid,ll,rr,lll)+query(mid+1,r,ll,rr,rrr))%mod; 97 } 98 void Basic_dfs(int x,int f) 99 { 100 p[x].fa=f; 101 p[x].dp=p[f].dp+1; 102 p[x].wgt=1; 103 int maxs=-1; 104 for(int i=p[x].hd;i;i=e[i].lst) 105 { 106 int to=e[i].twd; 107 if(to==f) 108 continue; 109 Basic_dfs(to,x); 110 p[x].wgt+=p[to].wgt; 111 if(p[to].wgt>maxs) 112 { 113 maxs=p[to].wgt; 114 p[x].mxs=to; 115 } 116 } 117 } 118 void Build_dfs(int x,int top) 119 { 120 if(!x) 121 return ; 122 p[x].ind=++dfn; 123 p[x].tp=top; 124 Build_dfs(p[x].mxs,top); 125 for(int i=p[x].hd;i;i=e[i].lst) 126 { 127 int to=e[i].twd; 128 if(p[to].ind) 129 continue; 130 Build_dfs(to,to); 131 } 132 return ; 133 } 134 void Insert(int x) 135 { 136 while(p[x].tp!=1) 137 { 138 update(1,n,p[p[x].tp].ind,p[x].ind,1,1); 139 x=p[p[x].tp].fa; 140 } 141 update(1,n,1,p[x].ind,1,1); 142 return ; 143 } 144 lnt Val(int x) 145 { 146 lnt ansl=0; 147 while(p[x].tp!=1) 148 { 149 ansl+=query(1,n,p[p[x].tp].ind,p[x].ind,1); 150 ansl%=mod; 151 x=p[p[x].tp].fa; 152 } 153 ansl+=query(1,n,1,p[x].ind,1); 154 ansl%=mod; 155 return ansl; 156 } 157 int main() 158 { 159 scanf("%d%d",&n,&q); 160 for(int i=2;i<=n;i++) 161 { 162 int a; 163 scanf("%d",&a); 164 a++; 165 ade(a,i); 166 ade(i,a); 167 } 168 cnt=0; 169 for(int i=1;i<=q;i++) 170 { 171 int tmp; 172 cnt++; 173 dt[cnt].no=i; 174 dt[cnt].lft=true; 175 scanf("%d",&dt[cnt].rgt); 176 cnt++; 177 dt[cnt].no=i; 178 dt[cnt].lft=false; 179 scanf("%d",&dt[cnt].rgt); 180 dt[cnt].rgt++; 181 scanf("%d",&tmp); 182 tmp++; 183 dt[cnt].z=dt[cnt-1].z=tmp; 184 } 185 sort(dt+1,dt+cnt+1,cmp); 186 Basic_dfs(1,1); 187 Build_dfs(1,1); 188 int plc=1; 189 for(int i=1;i<=cnt;i++) 190 { 191 while(plc<=dt[i].rgt) 192 { 193 Insert(plc); 194 plc++; 195 } 196 int x=dt[i].no; 197 int pl=dt[i].z; 198 lnt tmp=Val(pl); 199 if(dt[i].lft) 200 tmp=-tmp; 201 ans[x]=(ans[x]+tmp)%mod; 202 } 203 for(int i=1;i<=q;i++) 204 printf("%lld\n",(ans[i]%mod+mod)%mod); 205 return 0; 206 }