【题意】
【题解】
开始做这道题的时候抓住 lca 不放, 想了一些不太优美的做法 。
优美的正解:
考虑 与 z 的 lca 是 x 的点: 这时候 z 一定是 x 的一个后代, 而这些点 也都是 x 的一个后代 且 与 z 不属于 一个 x 的子节点 的枝 上。
x 这个点对 答案的 贡献就是 depth[x] * 上述点的个数。
显然“上述点” 的个数 应该是 sum(fat[x]) - sum(x),而这个数如果一直 加到根的话 是可以消掉的,,还是挺显然的,,
然后…… 这不是煞笔题么, 就是维护一个子树的大小啊。
把询问离线, 然后从 1 到 n 把点加进去, 每加进去一个点 就把 从 它 到 根 这一条路上的所有点 的子树大小都加上一, 裸树剖。
#include
#include
#include
#include
#include
#define MAXN 50005
#define mod 201314
using namespace std;
int aa[MAXN], cnt, n, q, ee, head[MAXN], dep[MAXN], sz[MAXN], son[MAXN], top[MAXN], ti[MAXN], fat[MAXN], ans[MAXN], lala;
struct Tree{int l, r, tag, sum;}tree[MAXN * 4];
struct Edge{int to, next;}edge[MAXN * 2];
struct La{int wei, id, flag, z;}la[MAXN * 2];
bool operator < (La a, La b){return a.wei < b.wei;}
inline void addedge(int x, int y){edge[++ ee].to = y; edge[ee].next = head[x]; head[x] = ee;}
void dfs1(int x, int fatt){
dep[x] = dep[fatt] + 1; sz[x] = 1; fat[x] = fatt; son[x] = 0;
for(int i = head[x]; i != -1; i = edge[i].next)if(edge[i].to != fatt){
dfs1(edge[i].to, x), sz[x] += sz[edge[i].to];
if(sz[edge[i].to] > sz[son[x]]) son[x] = edge[i].to;
}
}
void dfs2(int x, int fatt){
top[x] = fatt; ti[x] = ++ cnt;
if(son[x])dfs2(son[x], top[x]);
for(int i = head[x]; i != -1; i = edge[i].next)
if(edge[i].to != fat[x] && edge[i].to != son[x])dfs2(edge[i].to, edge[i].to);
}
void build(int t, int l, int r){
tree[t].l = l; tree[t].r = r; tree[t].sum = tree[t].tag = 0;
if(l == r)return; int mid = l + r >> 1;
build(t + t, l, mid); build(t + t + 1, mid + 1, r);
}
inline void pushdown(int t){if(!tree[t].tag)return;
(tree[t + t].tag += tree[t].tag) %= mod; (tree[t + t].sum += (tree[t].tag * (long long)(tree[t + t].r - tree[t + t].l + 1)) % mod) %= mod;
(tree[t + t + 1].tag += tree[t].tag) %= mod; (tree[t + t + 1].sum += (tree[t].tag * (long long)(tree[t + t + 1].r - tree[t + t + 1].l + 1)) % mod) %= mod;
tree[t].tag = 0;
}
inline void pushup(int t){tree[t].sum = (tree[t + t].sum + tree[t + t + 1].sum) % mod;}
void update(int t, int l, int r){
if(tree[t].l >= l && r >= tree[t].r){
(tree[t].sum += tree[t].r - tree[t].l + 1) %= mod; tree[t].tag ++; return;}
int mid = tree[t].l + tree[t].r >> 1;
pushdown(t);
if(l <= mid)update(t + t, l, r);
if(r >= mid + 1)update(t + t + 1, l, r);
pushup(t);
}
void add(int x){
int l = ti[top[x]], r = ti[x];
update(1, l, r);
if(top[x] != 1)add(fat[top[x]]);
}
int askk(int t, int l, int r){
if(tree[t].l >= l && r >= tree[t].r){return tree[t].sum;}
int mid = tree[t].l + tree[t].r >> 1, ret = 0;
pushdown(t);
if(l <= mid) ret += askk(t + t, l, r);
if(r >= mid + 1) ret += askk(t + t + 1, l, r);
return ret% mod;
}
int ask(int x){
int l = ti[top[x]], r = ti[x];if(l == 0 || r == 0)return 0;
int ret = askk(1, l, r);
return (ret + (top[x] == 1 ? 0 : ask(fat[top[x]]))) % mod;
}
int main()
{
scanf("%d%d", &n, &q);
memset(head, -1, sizeof(head));
for(int i = 2; i <= n; i ++){int x; scanf("%d", &x); addedge(x + 1, i);}
dfs1(1, 1); dfs2(1, 1);
build(1, 1, n);
for(int i = 1; i <= q; i ++){
int l, r, z; scanf("%d%d%d", &l, &r, &z);l ++; r ++; z ++;
la[++ lala].wei = l - 1; la[lala].id = i; la[lala].flag = 0; la[lala].z = z;
la[++ lala].wei = r; la[lala].id = i; la[lala].flag = 1; la[lala].z = z;
}
sort(la + 1, la + lala + 1);int ll = 1;
for(int i = 1; i <= lala; i ++){
while(ll <= n && ll <= la[i].wei){add(ll); ll ++; }
int ha = ask(la[i].z);
if(la[i].flag)ans[la[i].id] += ha;
else ans[la[i].id] -= ha;
}
for(int i = 1; i <= q; i ++)printf("%d\n", (ans[i] + mod) % mod);
return 0;
}
这么简单的东西我硬是调了一个上午,,
因为 取模的时候 %= 写成了 % , 还有 最后的时候 (x + mod) % mod 没有加,,,
%¥#%¥&%**%&*&%& 这都什么逗比错误啊!!!受不了我自己了。
【总结反思】
以后 写取模的时候不要最后 再写, 最后写我就会因为 刚拍完一题然后心情很激动然后写得时候 就会飘飘然, 控制不住自己, 然后错一些莫名奇妙的错误,,,T^T