弹球弹弹弹

题目大意:有n个位置,标号为1到n的整数,m次操作,第i次操作放置一个弹球在b[i] xor c[i-1]处,并询问b[i] xor c[i-1]处弹球个数c[i]每次操作后,在x处的弹球被弹到a[x],规定c[0]=0。

数据范围:1<=n,m<=500000。


题解

这个题真的是,说起来容易写起来是真的恶心.....

首先要读题,每次操作是这样的:

先加进来一个球,然后查询当前位置的个数,接着直接把每个位置弹到对应位置。

显然,每个点有一条出边,这是一个基环内向森林的模型。

我们把询问分成两种情况讨论:第一种是查询不在环上的点,第二种是环上的点。

第一种怎么弄呢?

首先发现,如果一个球进了环就出不来了,所以我们只需要统计这个点子树内的情况(我们以基环树的环为根,每个数的根就是对应环上的点)。

发现,如果一个点子树内的点$u$满足加入树的时间$time_u$加上和当前点的距离$dep[u]-dep[now]$等于当前时间$nowtime$的话,这个点就可以被统计到。

故此把每个点的权值设为$time_x+dep_x$,只需要查询当前点的子树中,权值等于$nowtime+dep[x]$的点个数。

这个可以用线段树平衡树啊什么的实现,我这里用的是线段树

具体地,我们对于每个权值开一棵线段树,最多需要开$maxtime + maxdep$棵。

线段树上每个节点维护其管辖区间里,所有权值等于当前线段树权值的点个数。

修改就直接在对应权值里修改就好了。

好,第一种情况我们就处理完了,复杂度是$O(nlogn)$。

看第二种情况。

第二种情况的答案贡献有两个渠道,第一个是本身修改就在环上修改的点,第二个是从树上走到环里的点。

第一个好弄,我们对每个环建立一个循环数组,环上每个点有个偏移量$skew_x$表示其距离环上拟定$0$号点的距离。

每次修改我们都直接修改到对应的节点上,就是修改到一次都没弹过的节点上,查询也上那儿查。

第一个就弄完了。

看看第二个:

第二个的话,就是修改是在树上修改,但是走到环上了。

怎么办呢?我们就弄一个$vector$叫$Fix_time$。

$Fix_i$表示所有在第$i$时刻的点集合。

对于一个在树上修改的点,我们把它扔进$Fix_{dep[x]+nowtime}$。

当处理完修改和查询之后,我们处理当前时刻的$Fix$数组。

每次只需要看一下,对应的点需要加到没有弹过的哪个环上节点就好了。

难写难调。

还有,这个题好像平衡树卡常,线段树秒过。

我写的线段树

代码

这个是删掉所有调试注释的,方便取用。

  1. #include <bits/stdc++.h>
  2.  
  3. #define N 500010
  4.  
  5. using namespace std;
  6.  
  7. struct Edge {
  8. int to[N << 1], nxt[N << 1], tot, head[N];
  9. inline void add(int x, int y) {
  10. to[ ++ tot] = y;
  11. nxt[tot] = head[x];
  12. head[x] = tot;
  13. }
  14. }G1,G2;
  15.  
  16. int d[N], dep[N], qu[N], dfn[N], Q[N], vis[N], sk[N], sz[N], top[N];
  17.  
  18. int root[N << 1];
  19.  
  20. bool disp[N];
  21.  
  22. queue<int> q;
  23.  
  24. vector<int> Round[N], Ans[N];
  25.  
  26. int cnt;
  27.  
  28. vector<int> Fix[N << 1];
  29.  
  30. struct Segment_Tree {
  31. int ls, rs, sum;
  32. }a[N << 8];
  33.  
  34. char *p1, *p2, buf[100000];
  35.  
  36. #define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ )
  37.  
  38. int rd() {
  39. int x = 0, f = 1;
  40. char c = nc();
  41. while (c < 48) {
  42. if (c == '-')
  43. f = -1;
  44. c = nc();
  45. }
  46. while (c > 47) {
  47. x = (((x << 2) + x) << 1) + (c ^ 48), c = nc();
  48. }
  49. return x * f;
  50. }
  51.  
  52. int n;
  53.  
  54. void toposort() {
  55. for (int i = 1; i <= n; i ++ ) {
  56. if (!d[i]) {
  57. vis[i] = -1;
  58. q.push(i);
  59. }
  60. }
  61. while (!q.empty()) {
  62. int x = q.front();
  63. q.pop();
  64. for (int i = G1.head[x]; i; i = G1.nxt[i]) {
  65. d[G1.to[i]] -- ;
  66. if (!d[G1.to[i]]) {
  67. q.push(G1.to[i]);
  68. vis[G1.to[i]] = -1;
  69. }
  70. }
  71. }
  72. }
  73.  
  74. inline void pushup(int x) {
  75. int ls = a[x].ls, rs = a[x].rs;
  76. a[x].sum = 0;
  77. if (ls) {
  78. a[x].sum += a[ls].sum;
  79. }
  80. if (rs) {
  81. a[x].sum += a[rs].sum;
  82. }
  83. }
  84.  
  85. void update(int x, int val, int l, int r, int &p) {
  86. if (!p) {
  87. p = ++cnt;
  88. }
  89. if (l == r) {
  90. a[p].sum ++ ;
  91. return;
  92. }
  93. int mid = (l + r) >> 1;
  94. if (x <= mid) {
  95. update(x, val, l, mid, a[p].ls);
  96. }
  97. else {
  98. update(x, val, mid + 1, r, a[p].rs);
  99. }
  100. pushup(p);
  101. }
  102.  
  103. int query(int x, int y, int l, int r, int p) {
  104. if (!p) {
  105. return 0;
  106. }
  107. if (x <= l && r <= y) {
  108. return a[p].sum;
  109. }
  110. int mid = (l + r) >> 1, ans = 0;
  111. if (x <= mid) {
  112. ans += query(x, y, l, mid, a[p].ls);
  113. }
  114. if (mid < y) {
  115. ans += query(x, y, mid + 1, r, a[p].rs);
  116. }
  117. return ans;
  118. }
  119.  
  120. void dfs_init(int p, int fa, int anc) {
  121. dfn[p] = ++dfn[0];
  122. top[p] = anc;
  123. sz[p] = 1;
  124. dep[p] = dep[fa] + 1;
  125. for (int i = G2.head[p]; i; i = G2.nxt[i]) {
  126. if (G2.to[i] != fa && vis[G2.to[i]] == -1) {
  127. dfs_init(G2.to[i], p, anc);
  128. sz[p] += sz[G2.to[i]];
  129. }
  130. }
  131. }
  132.  
  133. int main() {
  134. n = rd();
  135. for (int i = 1; i <= n; i ++ ) {
  136. qu[i] = rd();
  137. G1.add(i, qu[i]);
  138. d[qu[i]] ++ ;
  139. }
  140.  
  141. toposort();
  142. for (int i = 1; i <= n; i ++ ) {
  143. if (vis[i]) {
  144. G2.add(qu[i], i);
  145. }
  146. }
  147.  
  148. for (int i = 1; i <= n; i ++ ) {
  149. if (!vis[i] && !disp[i]) {
  150. vis[0] ++ ;
  151. int t = i;
  152. int now = 0;
  153. do {
  154. vis[t] = vis[0];
  155. disp[t] = true;
  156. Round[vis[0]].push_back(t);
  157. Ans[vis[0]].push_back(0);
  158. now ++ ;
  159. sk[t] = now - 1;
  160.  
  161. dfs_init(t, t, t);
  162.  
  163. t = qu[t];
  164. } while(t != i);
  165. }
  166. }
  167.  
  168. int m = rd();
  169. int lastans = 0;
  170. for (int i = 1; i <= m; i ++ ) {
  171. int x = rd();
  172. if (vis[x] == -1) {
  173. update(dfn[x], 1, 1, n, root[i + dep[x]]);
  174. lastans = query(dfn[x], dfn[x] + sz[x] - 1, 1, n, root[i + dep[x]]);
  175. printf("%d\n", lastans);
  176. Fix[i + dep[x] - 2].push_back(x);
  177. }
  178. else {
  179. int Round_length = Round[vis[x]].size();
  180. int now_position = ((sk[x] - i + 1) % Round_length + Round_length) % Round_length;
  181. Ans[vis[x]][now_position] ++ ;
  182. lastans = Ans[vis[x]][now_position];
  183. printf("%d\n", lastans);
  184. }
  185. int len = Fix[i].size();
  186. for (int j = 0; j < len; j ++ ) {
  187. int y = top[Fix[i][j]];
  188. int Round_length = Round[vis[y]].size();
  189. int now_position = ((sk[y] - i) % Round_length + Round_length) %Round_length;
  190. Ans[vis[y]][now_position] ++ ;
  191. }
  192. }
  193. return 0;
  194. }

这个嘛....是调的时候加的调试信息....博主只会用输出调试所以调完的代码都比较壮观,这个题恶心我两个小时特殊记录一下.....(有兴趣可以看看爽一爽顺便$diss$博主傻逼/xk)

  1. #include <bits/stdc++.h>
  2.  
  3. #define N 500010
  4.  
  5. using namespace std;
  6.  
  7. struct Edge {
  8. int to[N << 1], nxt[N << 1], tot, head[N];
  9. inline void add(int x, int y) {
  10. to[ ++ tot] = y;
  11. nxt[tot] = head[x];
  12. head[x] = tot;
  13. }
  14. }G1,G2;
  15.  
  16. int d[N], dep[N], qu[N], dfn[N], Q[N], vis[N], sk[N], sz[N], top[N];
  17.  
  18. int root[N << 1];
  19.  
  20. bool disp[N];
  21.  
  22. queue<int> q;
  23.  
  24. vector<int> Round[N], Ans[N];
  25.  
  26. int cnt;
  27.  
  28. vector<int> Fix[N << 1];
  29.  
  30. struct Segment_Tree {
  31. int ls, rs, sum;
  32. }a[N << 8];
  33.  
  34. char *p1, *p2, buf[100000];
  35.  
  36. #define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ )
  37.  
  38. int rd() {
  39. int x = 0, f = 1;
  40. char c = nc();
  41. while (c < 48) {
  42. if (c == '-')
  43. f = -1;
  44. c = nc();
  45. }
  46. while (c > 47) {
  47. x = (((x << 2) + x) << 1) + (c ^ 48), c = nc();
  48. }
  49. return x * f;
  50. }
  51.  
  52. int n;
  53.  
  54. void toposort() {
  55. for (int i = 1; i <= n; i ++ ) {
  56. if (!d[i]) {
  57. vis[i] = -1;
  58. q.push(i);
  59. }
  60. }
  61. while (!q.empty()) {
  62. int x = q.front();
  63. q.pop();
  64. for (int i = G1.head[x]; i; i = G1.nxt[i]) {
  65. d[G1.to[i]] -- ;
  66. if (!d[G1.to[i]]) {
  67. q.push(G1.to[i]);
  68. vis[G1.to[i]] = -1;
  69. }
  70. }
  71. }
  72. }
  73.  
  74. inline void pushup(int x) {
  75. int ls = a[x].ls, rs = a[x].rs;
  76. a[x].sum = 0;
  77. if (ls) {
  78. a[x].sum += a[ls].sum;
  79. }
  80. if (rs) {
  81. a[x].sum += a[rs].sum;
  82. }
  83. }
  84.  
  85. void update(int x, int val, int l, int r, int &p) {
  86. // printf("A %d %d %d %d %d %d\n", x, val, l, r, p, a[p].sum);
  87. if (!p) {
  88. p = ++cnt;
  89. }
  90. // printf("B %d %d %d %d %d %d\n", x, val, l, r, p, a[p].sum);
  91. if (l == r) {
  92. a[p].sum ++ ;
  93. return;
  94. }
  95. // printf("C %d %d %d %d %d %d\n", x, val, l, r, p, a[p].sum);
  96. int mid = (l + r) >> 1;
  97. if (x <= mid) {
  98. update(x, val, l, mid, a[p].ls);
  99. }
  100. else {
  101. update(x, val, mid + 1, r, a[p].rs);
  102. }
  103. pushup(p);
  104. // printf("D %d %d %d %d %d %d\n", x, val, l, r, p, a[p].sum);
  105. }
  106.  
  107. int query(int x, int y, int l, int r, int p) {
  108. if (!p) {
  109. return 0;
  110. }
  111. if (x <= l && r <= y) {
  112. return a[p].sum;
  113. }
  114. int mid = (l + r) >> 1, ans = 0;
  115. if (x <= mid) {
  116. ans += query(x, y, l, mid, a[p].ls);
  117. }
  118. if (mid < y) {
  119. ans += query(x, y, mid + 1, r, a[p].rs);
  120. }
  121. return ans;
  122. }
  123.  
  124. void dfs_init(int p, int fa, int anc) {
  125. dfn[p] = ++dfn[0];
  126. top[p] = anc;
  127. sz[p] = 1;
  128. dep[p] = dep[fa] + 1;
  129. for (int i = G2.head[p]; i; i = G2.nxt[i]) {
  130. if (G2.to[i] != fa && vis[G2.to[i]] == -1) {
  131. dfs_init(G2.to[i], p, anc);
  132. sz[p] += sz[G2.to[i]];
  133. }
  134. }
  135. }
  136.  
  137. int main() {
  138. n = rd();
  139. for (int i = 1; i <= n; i ++ ) {
  140. qu[i] = rd();
  141. G1.add(i, qu[i]);
  142. d[qu[i]] ++ ;
  143. }
  144.  
  145. toposort();
  146. for (int i = 1; i <= n; i ++ ) {
  147. if (vis[i]) {
  148. G2.add(qu[i], i);
  149. }
  150. }
  151.  
  152. // for (int i = 1; i <= n; i ++ ) {
  153. // printf("%d ",vis[i]);
  154. // }
  155. // puts("");
  156.  
  157. for (int i = 1; i <= n; i ++ ) {
  158. if (!vis[i] && !disp[i]) {
  159. // printf("i-> %d\n", i);
  160. vis[0] ++ ;
  161. int t = i;
  162. int now = 0;
  163. do {
  164. // printf("t-> %d\n", t);
  165. vis[t] = vis[0];
  166. disp[t] = true;
  167. Round[vis[0]].push_back(t);
  168. Ans[vis[0]].push_back(0);
  169. now ++ ;
  170. sk[t] = now - 1;
  171.  
  172. dfs_init(t, t, t);
  173.  
  174. t = qu[t];
  175. // printf("t-> %d\n", t);
  176. } while(t != i);
  177. // while (t != i) {
  178. // vis[t] = vis[0];
  179. // disp[t] = true;
  180. // Round[vis[0]].push_back(t);
  181. // Ans[vis[0]].push_back(0);
  182. // now ++ ;
  183. // sk[t] = now - 1;
  184.  
  185. // dfs_init(t, t, t);
  186.  
  187. // t = qu[t];
  188. // }
  189. }
  190. }
  191.  
  192. // puts("Fuck");
  193.  
  194. // printf("%d %d %d %d\n", sk[2], sk[4], sk[7], sk[10]);
  195.  
  196. int m = rd();
  197. int lastans = 0;
  198. for (int i = 1; i <= m; i ++ ) {
  199. int x = rd();
  200. // x ^= lastans;
  201. // printf("i- %d\n", i);
  202. if (vis[x] == -1) {
  203. // printf("A\n");
  204. // printf("%d\n", i + dep[x]);
  205. update(dfn[x], 1, 1, n, root[i + dep[x]]);
  206. lastans = query(dfn[x], dfn[x] + sz[x] - 1, 1, n, root[i + dep[x]]);
  207. printf("%d\n", lastans);
  208. // printf("Fix %d\n", i + dep[x] - 2);
  209. Fix[i + dep[x] - 2].push_back(x);
  210. }
  211. else {
  212. int Round_length = Round[vis[x]].size();
  213. int now_position = ((sk[x] - i + 1) % Round_length + Round_length) % Round_length;
  214. // printf("%d %d\n", Round_length, now_position);
  215. Ans[vis[x]][now_position] ++ ;
  216. lastans = Ans[vis[x]][now_position];
  217. printf("%d\n", lastans);
  218. }
  219. int len = Fix[i].size();
  220. for (int j = 0; j < len; j ++ ) {
  221. // Fix[i][j];
  222. int y = top[Fix[i][j]];
  223. int Round_length = Round[vis[y]].size();
  224. int now_position = ((sk[y] - i) % Round_length + Round_length) %Round_length;
  225. // printf("np %d\n", now_position);
  226. // printf("%d %d\n", Round_length, now_position);
  227. Ans[vis[y]][now_position] ++ ;
  228. }
  229. }
  230. return 0;
  231. }
  232. /*
  233. 6
  234. 1
  235. 2
  236. 1
  237. 3
  238. 3
  239. 6
  240. 20
  241. 1
  242. 2
  243. 3
  244. 4
  245. 5
  246. 6
  247. 1
  248. 2
  249. 3
  250. 4
  251. 5
  252. 6
  253. 1
  254. 2
  255. 3
  256. 4
  257. 5
  258. 6
  259. 6
  260. 6
  261. */
  262. /*
  263. 1 1 1 1 1 1 5 2 1 1 1 2 9 3 1 1 1 3 4 5
  264.  
  265. */

小结:好题好题,这个出成考试题非常妙啊,好想诶,就是有点难写。当然只是对我来讲,别人肯定分分钟切掉。

[Nowcoder113E]弹球弹弹弹_线段树的更多相关文章

  1. BZOJ_4636_蒟蒻的数列_线段树+动态开点

    BZOJ_4636_蒟蒻的数列_线段树+动态开点 Description 蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列 题目描述 DCrusher有一个数列,初始值均为0,他进行N次操作,每次将 ...

  2. BZOJ_3252_攻略_线段树+dfs序

    BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...

  3. BZOJ_4653_[Noi2016]区间_线段树+离散化+双指针

    BZOJ_4653_[Noi2016]区间_线段树+离散化+双指针 Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间, ...

  4. BZOJ_2124_等差子序列_线段树+Hash

    BZOJ_2124_等差子序列_线段树+Hash Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pL ...

  5. BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心

    BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心 Description 在计算机中,CPU只能和高速缓存Cache直接交换数据.当所需的内存单元不在Cache中时,则需要从主存里把数 ...

  6. BZOJ_1828_[Usaco2010 Mar]balloc 农场分配_线段树

    BZOJ_1828_[Usaco2010 Mar]balloc 农场分配_线段树 Description Input 第1行:两个用空格隔开的整数:N和M * 第2行到N+1行:第i+1行表示一个整数 ...

  7. BZOJ_1798_[AHOI2009]维护序列_线段树

    BZOJ_1798_[AHOI2009]维护序列_线段树 题意:老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: ( ...

  8. BZOJ_3307_雨天的尾巴_线段树合并+树上差分

    BZOJ_3307_雨天的尾巴_线段树合并 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后 ...

  9. BZOJ_1858_[Scoi2010]序列操作_线段树

    BZOJ_1858_[Scoi2010]序列操作_线段树 Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询 ...

  10. BZOJ_2957_楼房重建_线段树

    BZOJ_2957_楼房重建_线段树 Description 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多 ...

随机推荐

  1. Educational Codeforces Round 34 (Rated for Div. 2) B题【打怪模拟】

    B. The Modcrab Vova is again playing some computer game, now an RPG. In the game Vova's character re ...

  2. PHP mysqli_fetch_fields() 函数

    mysqli_fetch_fields() 函数返回结果集中代表字段(列)的对象的数组. 返回结果集中代表字段(列)的对象的数组,然后输出每个字段名称.表格和最大长度: <?php // 假定数 ...

  3. BZOJ 2165: 大楼 倍增Floyd

    卡了一上午常数,本地13s,可是bzoj 就是过不去~ #include <bits/stdc++.h> #define N 102 #define M 55 #define ll lon ...

  4. HGOI 20191103am 题解

    Problem A number 使用一个$2^k$数集中每个元素的和表示数$n$,不同集合的数目有多少? 对于$100\%$的数据满足$1 \leq n \leq 10^6$ Solution : ...

  5. Linux下 Nginx 启动 重启 关闭

    命令 nginx -s reload :修改配置后重新加载生效 nginx -s reopen :重新打开日志文件 nginx -t -c /path/to/nginx.conf 测试nginx配置文 ...

  6. 使用聚集索引和非聚集索引对MySQL分页查询的优化

    内容摘录来源:MSSQL123 ,lujun9972.github.io/blog/2018/03/13/如何编写bash-completion-script/ 一.先公布下结论: 1.如果分页排序字 ...

  7. airflow自动生成dag

    def auto_create_dag(): dag_list=[] dag = DAG() dag_list.append(dag) return dag_list dags = auto_crea ...

  8. 利用简易爬虫完成一道基础CTF题

    利用简易爬虫完成一道基础CTF题 声明:本文主要写给新手,侧重于表现使用爬虫爬取页面并提交数据的大致过程,所以没有对一些东西解释的很详细,比如表单,post,get方法,感兴趣的可以私信或评论给我.如 ...

  9. OUC_Summer Training_ DIV2_#14 724

    又落下好多题解啊...先把今天的写上好了. A - Snow Footprints Time Limit:1000MS     Memory Limit:262144KB     64bit IO F ...

  10. RunHelper,一个为跑步而设计的开源的android app

    RunHelper是一个为跑步而设计的android应用,意在为爱跑步的人提供一个简洁.实用.免费的工具. 我自己也经常跑步,也用过像Nike running.runkeeper之类的app:Nike ...