[LNOI2014]LCA
题解:
首先我们要转化一下,因为直接求不好求。首先考虑一个点对z的贡献,观察这么一个图:
显然点x对点z的贡献为2,因为LCA的深度为2。LCA可以看做点x和点z分别走向root的两条路径中第一个重合的点,因此,如果我们给x到root的路径上的点都赋1的点权,那么再从z往上走,
因为LCA是两条路径中第一个重合的点,因此我们会从LCA开始获取点权,那么走到root后得到的点权和刚好就是点x对点z的贡献!
因此我们直接做一个树链剖分,然后用线段树来维护区间加和区间查询即可。
然而直接对每个询问都这么做显然是会超时的,因此我们要考虑一些效率更高的做法。
因为每个询问都是一个区间的查询,而且符合区间减法,即对于同一点而言ans[1, r] - ans[1, l -1] = ans[l, r]。
这时思路就很明确了,我们可以从1开始枚举,依次进行区间加,然后每次加了之后就处理一遍相关的询问,跟tarjan求LCA的思想有一点点类似。
获取了ans[1, r] 和 ans[1, l - 1]后就可以很方便的求出ans[l, r]了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 50100 5 #define ac 500100 6 #define mod 201314 7 #define getchar() *o++ 8 char READ[5000100], *o = READ; 9 int n, m, cnt, rnt; 10 int Head[AC], Next[AC], date[AC], all; 11 int Size[AC], son[AC], father[AC], dep[AC], ans[AC], top[AC], id[AC], d[AC], last[AC]; 12 13 struct node{ 14 int Head[AC], Next[AC*2], date[AC*2], id[AC*2], tot;//error!!!询问会存2次啊,左端点和右端点啊,,,数组开两倍啊!!! 15 void add(int f, int w, int S)//存询问 16 { 17 date[++tot] = w, Next[tot] = Head[f], Head[f] = tot, id[tot] = S; 18 } 19 }E; 20 21 struct _question{ 22 int l, r, x; 23 }q[AC]; 24 25 inline void add(int f, int w) 26 { 27 date[++all] = w, Next[all] = Head[f], Head[f] = all; 28 } 29 30 inline int read() 31 { 32 int x = 0;char c = getchar(); 33 while(c > '9' || c < '0') c = getchar(); 34 while(c >= '0' && c <= '9') x = x * 10 + c -'0', c = getchar(); 35 return x; 36 } 37 38 void pre() 39 { 40 int a; 41 n = read(), m = read(); 42 for(R i = 2; i <= n; i++) 43 { 44 a = read() + 1;//编号从移到1开始算 45 add(a, i); 46 father[i] = a; 47 } 48 for(R i = 1; i <= m; i++) 49 { 50 q[i].l = read() + 1, q[i].r = read() + 1, q[i].x = read() + 1; 51 if(q[i].l > q[i].r) swap(q[i].l, q[i].r); 52 E.add(q[i].l - 1, q[i].x, i);//从前向后枚举点x差分,这样就会先遇到左端点, 53 E.add(q[i].r, q[i].x, i);//所以遇到右端点查询的时候就直接减就可以了 54 } 55 dep[1] = 1; 56 } 57 58 void dfs1(int x)//get Size, son, dep 59 { 60 int now, maxn = 0; 61 Size[x] = 1;//先加上自己 62 for(R i = Head[x]; i; i = Next[i]) 63 { 64 now = date[i]; 65 if(now == father[x]) continue; 66 dep[now] = dep[x] + 1; 67 dfs1(now); 68 Size[x] += Size[now]; 69 if(Size[now] > Size[maxn]) maxn = now; 70 } 71 son[x] = maxn; 72 } 73 74 void dfs2(int x, int topx)//get id, top 75 { 76 int now; 77 id[x] = ++cnt, top[x] = topx; 78 if(!son[x]) return ; 79 dfs2(son[x], topx);//重链需要继承 80 last[x] = son[x]; 81 for(R i = Head[x]; i; i = Next[i]) 82 { 83 now = date[i]; 84 if(now == father[x] || now == son[x]) continue;//如果是父亲or重儿子就跳过 85 dfs2(now, now);//新开链 86 } 87 } 88 89 int tree[ac], lazy[ac], l[ac], r[ac]; 90 91 void build(int x, int ll, int rr) 92 { 93 if(ll == rr) 94 { 95 l[x] = r[x] = ll; 96 return ; 97 } 98 l[x] = ll, r[x] = rr; 99 int mid = (ll + rr) >> 1; 100 build(x * 2, ll, mid); 101 build(x * 2 + 1, mid + 1, rr); 102 103 } 104 105 inline void pushdown(int x) 106 { 107 if(lazy[x]) 108 { 109 int ll = x * 2, rr = ll + 1; 110 lazy[ll] += lazy[x], lazy[rr] += lazy[x]; 111 tree[ll] += lazy[x] * (r[ll] - l[ll] + 1) , tree[rr] += lazy[x] * (r[rr] - l[rr] + 1); 112 lazy[x] = 0; 113 } 114 } 115 116 inline void update(int x) 117 { 118 tree[x] = tree[x * 2] + tree[x * 2 + 1]; 119 } 120 121 void add(int x, int ll, int rr)//区间加 122 { 123 pushdown(x); 124 if(l[x] == ll && r[x] == rr) 125 { 126 tree[x] += (rr - ll + 1); 127 lazy[x] += 1; 128 return ; 129 } 130 int mid = (l[x] + r[x]) >> 1; 131 if(rr <= mid) add(x * 2, ll, rr); 132 else if(ll > mid) add(x * 2 + 1, ll, rr); 133 else 134 { 135 add(x * 2, ll, mid); 136 add(x * 2 + 1, mid + 1, rr); 137 } 138 update(x); 139 } 140 141 void search(int x, int ll, int rr)//查询 142 { 143 pushdown(x); 144 if(l[x] == ll && r[x] == rr) 145 { 146 rnt += tree[x]; 147 return ; 148 } 149 int mid = (l[x] + r[x]) >> 1; 150 if(rr <= mid) search(x * 2, ll, rr); 151 else if(ll > mid) search(x * 2 + 1, ll, rr); 152 else 153 { 154 search(x * 2, ll, mid); 155 search(x * 2 + 1, mid + 1, rr); 156 } 157 } 158 159 void change(int x) 160 { 161 while(x) 162 { 163 add(1, id[top[x]], id[x]); 164 x = father[top[x]]; 165 } 166 if(x == 1) add(1, 1, 1);//如果不是0就会跳过1 167 168 } 169 170 int find(int x) 171 { 172 rnt = 0; 173 while(x) 174 { 175 search(1, id[top[x]], id[x]); 176 x = father[top[x]]; 177 } 178 if(x == 1) search(1, 1, 1); 179 return rnt; 180 } 181 182 void work() 183 { 184 int x; 185 for(R i = 1; i <= n; i++) 186 { 187 change(i);//修改i ---> root 188 for(R j = E.Head[i]; j; j = E.Next[j]) 189 { 190 x = E.date[j];//获取z 191 ans[E.id[j]] = (find(x) - ans[E.id[j]]) % mod; 192 } 193 } 194 for(R i = 1; i <= m; i++) printf("%d\n", ans[i]); 195 } 196 197 int main() 198 { 199 // freopen("in.in", "r", stdin); 200 fread(READ, 1, 5000000, stdin); 201 pre(); 202 dfs1(1); 203 dfs2(1, 1); 204 build(1, 1, n); 205 work(); 206 // fclose(stdin); 207 return 0; 208 }