BZOJ3553 [Shoi2014]三叉神经树

容易想到树链剖分来维护

一条链上维护儿子中是1的个数为1的点的最长值和儿子是1的个数为2的点的最长值

于是每次修改的时候就二分查询会更新到哪里,再直接链修改就好了

单次查询复杂度$O(logn^2)$,单次修改复杂度为$O(logn)$

注意如果动态开点太多会导致MLE,最后解决办法是在每个线段树节点上增加了一个res变量表示返回值

  1 /**************************************************************
  2     Problem: 3553
  3     User: rausen
  4     Language: C++
  5     Result: Accepted
  6     Time:18880 ms
  7     Memory:102672 kb
  8 ****************************************************************/
  9
 10 #include <cstdio>
 11
 12 using namespace std;
 13 const int N = 5e5 + 5;
 14
 15 inline int read();
 16
 17 int n;
 18 int seq[N * 3];
 19
 20 struct tree_node {
 21     int v, dep, sz;
 22     int son[3], fa, top, w;
 23 } tr[N * 3];
 24
 25 struct seg {
 26     seg *ls, *rs, *res;
 27     int tag, mx[2], sz;
 28
 29     #define Len (1 << 16)
 30     inline void* operator new (size_t) {
 31         static seg *mempool, *c;
 32         if (c == mempool)
 33             mempool = (c = new seg[Len]) + Len;
 34         c -> ls = c -> rs = c -> res = NULL;
 35         c -> tag = -1, c -> sz = 1, c -> mx[0] = c -> mx[1] = 0;
 36         return c++;
 37     }
 38     #undef Len
 39
 40     inline void fill(int x) {
 41         tag = x;
 42         mx[0] = mx[1] = 0;
 43         if (tag == 1) mx[0] = sz;
 44         if (tag == 2) mx[1] = sz;
 45     }
 46     inline void push() {
 47         if (tag != -1) {
 48             if (ls) ls -> fill(tag);
 49             if (rs) rs -> fill(tag);
 50             tag = -1;
 51         }
 52     }
 53     inline void update(seg *t1, seg *t2) {
 54         sz = t1 -> sz + t2 -> sz;
 55         mx[0] = t2 -> mx[0] + (t2 -> mx[0] == t2 -> sz ? t1 -> mx[0] : 0);
 56         mx[1] = t2 -> mx[1] + (t2 -> mx[1] == t2 -> sz ? t1 -> mx[1] : 0);
 57     }
 58
 59     #define mid (l + r >> 1)
 60     void build(int l, int r) {
 61         if (l == r) {
 62             fill(tr[seq[l]].v);
 63             return;
 64         }
 65         ls = new()seg, rs = new()seg, res = new()seg;
 66         ls -> build(l, mid), rs -> build(mid + 1, r);
 67         update(ls, rs);
 68     }
 69
 70     void modify(int l, int r, int L, int R, int d) {
 71         if (L <= l && r <= R) {
 72             fill(d);
 73             return;
 74         }
 75         push();
 76         if (L <= mid) ls -> modify(l, mid, L, R, d);
 77         if (mid < R) rs -> modify(mid + 1, r, L, R, d);
 78         update(ls, rs);
 79     }
 80
 81     int query(int l, int r, int pos) {
 82         if (l == r) return tag;
 83         push();
 84         if (pos <= mid) return ls -> query(l, mid, pos);
 85         else return rs -> query(mid + 1, r, pos);
 86     }
 87     seg* query(int l, int r, int L, int R) {
 88         if (L <= l && r <= R) return this;
 89         push();
 90         if (R <= mid) return ls -> query(l, mid, L, R);
 91         if (mid < L) return rs -> query(mid + 1, r, L, R);
 92         res -> update(ls -> query(l, mid, L, R), rs -> query(mid + 1, r, L, R));
 93         return res;
 94     }
 95     #undef mid
 96 } *T;
 97
 98 inline void modify(int p, int tar, int c) {
 99     while (tr[p].top != tr[tar].top)
100         T -> modify(1, n, tr[tr[p].top].w, tr[p].w, c), p = tr[tr[p].top].fa;
101     T -> modify(1, n, tr[tar].w, tr[p].w, c);
102 }
103
104 int change(int p) {
105     static int c, now, q;
106     static seg *tmp;
107     c = tr[p].v, now = tr[p].fa, tr[p].v = 1 - tr[p].v;
108     while (1) {
109         tmp = T -> query(1, n, tr[tr[now].top].w, tr[now].w);
110         if (tmp -> sz != tmp -> mx[c]) break;
111         now = tr[now].top;
112         if (!tr[now].fa || T -> query(1, n, tr[tr[now].fa].w) != c + 1) break;
113         now = tr[now].fa;
114     }
115     if (T -> query(1, n, tr[now].w) != c + 1) {
116         T -> modify(1, n, tr[now].w, tr[now].w, T -> query(1, n, tr[now].w) + (c ? -1 : 1));
117         return T -> query(1, n, 1) >= 2;
118     }
119     if (now == tr[now].top) q = now;
120     else q = seq[tr[now].w - T -> query(1, n, tr[tr[now].top].w, tr[now].w) -> mx[c] + 1];
121     modify(tr[p].fa, q, tr[p].v + 1);
122     if (tr[q].fa) T -> modify(1, n, tr[tr[q].fa].w, tr[tr[q].fa].w, T -> query(1, n, tr[tr[q].fa].w) + (c ? -1 : 1));
123     return T -> query(1, n, 1) >= 2;
124 }
125
126 void get_seq() {
127     static int i, j, q[N], tot_q, tot_d, p, S;
128     q[tot_q = 1] = 1, tr[1].fa = 0;
129     for (i = 1; i <= n; ++i)
130         for (j = 0; j < 3; ++j)
131             if (tr[q[i]].son[j] <= n)
132                 tr[q[++tot_q] = tr[q[i]].son[j]].dep = tr[q[i]].dep + 1;
133     for (i = 1; i <= n; ++i) tr[i].top = i, tr[i].sz = 1;
134     for (i = n; i; --i) tr[tr[q[i]].fa].sz += tr[q[i]].sz;
135
136     tr[0].sz = 0, tr[1].w = 1;
137     for (i = 1; i <= n; ++i) {
138         p = q[i], tot_d = tr[p].w;
139         for (j = S = 0; j < 3; ++j)
140             if (tr[p].son[j] <= n && tr[tr[p].son[j]].sz > tr[S].sz)
141                 S = tr[p].son[j];
142         if (S)
143             tr[S].w = tot_d + 1, tot_d += tr[S].sz, tr[S].top = tr[p].top;
144         for (j = 0; j < 3; ++j)
145             if (tr[p].son[j] <= n && tr[p].son[j] != S)
146                 tr[tr[p].son[j]].w = tot_d + 1, tot_d += tr[tr[p].son[j]].sz;
147     }
148     for (i = n; i; --i) if (tr[q[i]].v >= 2) ++tr[tr[q[i]].fa].v;
149     for (i = 1; i <= n; ++i) seq[tr[i].w] = i;
150 }
151
152 int main() {
153     int i, j, Q;
154     n = read();
155     for (i = 1; i <= n; ++i)
156         for (j = 0; j < 3; ++j)
157             tr[tr[i].son[j] = read()].fa = i;
158     for (i = n + 1; i <= 3 * n + 1; ++i)
159         tr[tr[i].fa].v += (tr[i].v = read());
160     get_seq();
161     T = new()seg, T -> build(1, n);
162     Q = read();
163     while (Q--)
164         printf("%d\n", change(read()));
165     return 0;
166 }
167
168 inline int read() {
169     static int x;
170     static char ch;
171     x = 0, ch = getchar();
172     while (ch < ‘0‘ || ‘9‘ < ch)
173         ch = getchar();
174     while (‘0‘ <= ch && ch <= ‘9‘) {
175         x = x * 10 + ch - ‘0‘;
176         ch = getchar();
177     }
178     return x;
179 }

(p.s. 论编程能力弱的后果。。。写了一下午,调了一晚上QAQQQ)

时间: 2024-10-28 20:02:20

BZOJ3553 [Shoi2014]三叉神经树的相关文章

[BZOJ 3553][SHOI2014]三叉神经树

传送门(下面也有题面) 题目大意: 一颗有根树,每个非叶子节点都有三个子节点,每个节点的权为0/1. 每个节点的权 取决于其所有子节点中 哪种权出现的次数更多. 有若干次询问,每次询问修改一个叶子节点的权,然后输出修改后根节点的权. 给出叶子节点初始值. 解法:树链剖分+线段树 叶子节点和非叶子节点的性质不同,为了省却麻烦,我们把叶子节点去掉, 每次修改叶子节点就直接修改其父亲.以下的“叶子节点”均指处理后的树的叶子节点. 如果用num[]记录每个节点的权为1的子节点个数, 那么当num[i]>

【BZOJ-3553】三叉神经树 树链剖分

3553: [Shoi2014]三叉神经树 Time Limit: 160 Sec  Memory Limit: 256 MBSubmit: 347  Solved: 112[Submit][Status][Discuss] Description 计算神经学作为新兴的交叉学科近些年来一直是学术界的热点.一种叫做SHOI 的神经组织因为其和近日发现的化合物 SHTSC 的密切联系引起了人们的极大关注.SHOI 组织由若干个 SHOI 细胞构成,SHOI 细胞之间形成严密的树形结构.每个 SHOI

[SHOI2014]三叉神经树

题目描述 计算神经学作为新兴的交叉学科近些年来一直是学术界的热点.一种叫做SHOI 的神经组织因为其和近日发现的化合物 SHTSC 的密切联系引起了人们的极大关注. SHOI 组织由若干个 SHOI 细胞构成,SHOI 细胞之间形成严密的树形结构.每个 SHOI 细胞都有且只有一个输出端,被称为轴突,除了一个特殊的.被称为根细胞的 SHOI 细胞的输出作为整个组织的输出以外,其余细胞的轴突均连向其上级 SHOI 细胞:并且有且只有三个接收端,被称为树突,从其下级细胞或者其它神经组织那里接收信息.

数据结构(下)

1.树套树 (1)树状数组套树状数组 前置: 树状数组如何支持区间加以及区间查询 维护一个差分数组,用来求一个位置的值,我们只需要把前缀和看作是一个矩形, 减去两数插值产生的贡献即可 1.P4514 上帝造题的七分钟 题意:支持矩形加某个数和矩形查询值. 考虑将每个点差分,当我们要将\((a,b),(x,y)\)范围内的矩阵加1时,其实就是: \(A(a,b)+1\) \(A(x,b+1)-1\) \(A(a,y+1)-1\) \(A(x+1,y+1)+1\) 于是乎,前缀和: \[\sum_{

[BZOJ 3637]Query on a tree VI

偶然看见了这题,觉得自己 QTREE.COT 什么的都没有刷过的真是弱爆了…… 一道思路很巧妙的题,终于是在约大爷的耐心教导下会了,真是太感谢约大爷了. 这题显然是树链剖分,但是链上维护的东西很恶心.其核心思想是找到一个相连的最浅同色节点,那么我只要维护每个点的子树中与他相连的点的数量即可 用 f[c][u] 表示在 u 的子树中与 u 相连 (假设 u 无色) 且颜色为 c 的点数 查询直接算出与 u 相连的最浅同色节点 a,ans=f[c[u]][a] 考虑修改,我们发现每次 u 被反转,影

bzoj 3566: [SHOI2014]概率充电器 树形DP

首先普及一个概率公式 P(A+B)=P(A)+P(B)-P(AB) 题意:一些充电元件和导线构成一棵树,充电元件是否能充电有2种情况, 1.它自己有qi%的概率充电 2.与它相邻的元件通过导线给它充电(导线有p%的概率导通) 求最终充了电的元件的期望 题解:首先可以将元件能否充电分成3种情况考虑, 1.它自己给自己充好了电 2.它的儿子方向给它传送了电 3.它的父亲方向给它传送了电. 对于1,题目已经给出可以直接赋值, 对于2,可以通过一次树的深度遍历求得.pson[now]=pson[now]

【BZOJ】3566: [SHOI2014]概率充电器

[算法]树型DP+期望DP [题意]一棵树上每个点均有直接充电概率qi%,每条边有导电概率pi%,问期望有多少结点处于充电状态? [题解]引用自:[BZOJ3566][SHOI2014]概率充电器 树形DP 概率DP by 空灰冰魂 最大的难点在于计算每个点充电期望时,两个节点各自的期望都会影响对方的期望. 所以考虑转化对象,改为求每个节点充不上电的期望,充不上电就不用考虑两者的相互影响. fi表示结点i由子结点和自身充不上电的概率 gi表示结点i由父结点充不上电的概率 第一次DFS: hi表示

HDU 6203 ping ping ping [LCA,贪心,DFS序,BIT(树状数组)]

题目链接:[http://acm.hdu.edu.cn/showproblem.php?pid=6203] 题意 :给出一棵树,如果(a,b)路径上有坏点,那么(a,b)之间不联通,给出一些不联通的点对,然后判断最少有多少个坏点. 题解 :求每个点对的LCA,然后根据LCA的深度排序.从LCA最深的点对开始,如果a或者b点已经有点被标记了,那么continue,否者标记(a,b)LCA的子树每个顶点加1. #include<Bits/stdc++.h> using namespace std;

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include