Love her~.|

cn_ryh

园龄:2年2个月粉丝:0关注:5

P4216 [SCOI2015] 情报传递题解

P4216 [SCOI2015] 情报传递 题解

来一篇常数不大的最优解题解。

洛谷题目

Solution

对于每个询问,第一问是基础的树上问题,公式放在下面,不在赘述。

dis(u,v)=depu+depv2×deplca(u,v)+1

首先,我们可以转化一下题意:题目求某条链上危险程度 大于 C 的节点数,而一个节点的危险程度又只与开始时间和查询时间有关,对于每个询问,查询时间是一定的,因此对于第 i 个询问,我们查询的就是 Xi\rArrYi 这条链上开始搜集情报时间在 iCi 之前的节点数。

每次清空重新查询复杂度是 \Omicron(n2log2n) 的。

考虑离线,由于只查询在 iCi 之前的点,因此我们可以将查询按照 iCi 排序。查询时我们先加入满足开始搜集情报时间在 iCi 之前的新点。

利用树链剖分,我们可以把 Xi\rArrYi 的路径拆分成若干 dfs 序连续的短链,我们可以利用树状数组查询这些短链上符合要求的点数。

时间复杂度 \Omicron(nlog2n),树状数组常数小,跑的飞快。

Codes

#include <bits/stdc++.h>
using namespace std;
#define max_n 200001
void read(int &p)
{
p = 0;
int k = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
{
k = -1;
}
c = getchar();
}
while (c >= '0' && c <= '9')
{
p = p * 10 + c - '0';
c = getchar();
}
p *= k;
return;
}
void write_(int x)
{
if (x < 0)
{
putchar('-');
x = -x;
}
if (x > 9)
{
write_(x / 10);
}
putchar(x % 10 + '0');
}
void writesp(int x)
{
write_(x);
putchar(' ');
}
void writeln(int x)
{
write_(x);
putchar('\n');
}
struct node
{
int to,nxt;
}edge[max_n];
int head[max_n],tot;
void add(int u,int v)
{
edge[++tot].to = v;
edge[tot].nxt = head[u];
head[u] = tot;
}
int n,q,root;
int fa[max_n],siz[max_n],dfn[max_n],rev[max_n],dep[max_n],son[max_n],top[max_n],timer;
void dfs1(int u)
{
dep[u] = dep[fa[u]] + 1;
siz[u] = 1;
for(int i = head[u];i;i = edge[i].nxt)
{
int v = edge[i].to;
dfs1(v);
siz[u] += siz[v];
if(siz[v] > siz[son[u]])
{
son[u] = v;
}
}
}
void dfs2(int u,int t)
{
dfn[u] = ++timer;
rev[timer] = u;
top[u] = t;
if(son[u])
{
dfs2(son[u],t);
}
for(int i = head[u];i;i = edge[i].nxt)
{
int v = edge[i].to;
if(v == son[u])
{
continue;
}
dfs2(v,v);
}
}
int ans[max_n];
struct Query
{
int u,v,lim,id,ans,cnt;
}ques[max_n];
struct Change
{
int id,tim;
}changes[max_n];
int tree[max_n];
int lowbit(int x)
{
return (-x) & x;
}
void update(int x)
{
for(;x <= n;x += lowbit(x))
{
tree[x]++;
}
}
int query(int x)
{
int res = 0;
for(;x;x -= lowbit(x))
{
res += tree[x];
}
return res;
}
int query(int l,int r)
{
return query(r) - query(l - 1);
}
signed main()
{
read(n);
for(int i = 1;i <= n;i++)
{
read(fa[i]);
if(fa[i])
{
add(fa[i],i);
}
else
{
root = i;
}
}
dfs1(root);
dfs2(root,root);
read(q);
int cnt = 0;
for(int i = 1,u,v,lim,op;i <= q;i++)
{
read(op);
if(op == 2)
{
read(u);
changes[i - cnt].id = u;
changes[i - cnt].tim = i;
}
else
{
++cnt;
read(u),read(v),read(lim);
ques[cnt].u = u;
ques[cnt].v = v;
ques[cnt].lim = lim;
ques[cnt].id = i;
}
}
sort(ques + 1,ques + cnt + 1,[](Query q1,Query q2){return (q1.id - q1.lim) < (q2.id - q2.lim);});;
int now = 1;
for(int i = 1;i <= cnt;++i)
{
while(now <= q - cnt && changes[now].tim < (ques[i].id - ques[i].lim))
{
update(dfn[changes[now].id]);
++now;
}
int u = ques[i].u,v = ques[i].v;
ques[i].cnt = dep[u] + dep[v];
while(top[u] != top[v])
{
if(dep[top[u]] < dep[top[v]])
{
swap(u,v);
}
ques[i].ans += query(dfn[top[u]],dfn[u]);
u = fa[top[u]];
}
if(dep[u] < dep[v])
{
swap(u,v);
}
ques[i].ans += query(dfn[v],dfn[u]);
ques[i].cnt -= 2 * dep[v] - 1;
}
sort(ques + 1,ques + cnt + 1,[](Query q1,Query q2){return q1.id < q2.id;});
for(int i = 1;i <= cnt;++i)
{
writesp(ques[i].cnt),writeln(ques[i].ans);
}
return 0;
}
posted @   cn_ryh  阅读(33)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起