一本通 高手训练 1763 简单树 可持久化线段树 树链刨分 标记永久化
Posted chdy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一本通 高手训练 1763 简单树 可持久化线段树 树链刨分 标记永久化相关的知识,希望对你有一定的参考价值。
LINK:简单树
以后我再不认真读题 我TM活该退役
又因为没认真读题多调了20min.时间珍贵啊。
题目最后让ans%n 我没取模 自闭ing.
还是挺有意思的题目。求x到区间[L,R]的所有点的距离。
这个还是一个非常经典的问题。需要把答案的式子列出来。
(sum_{i=L}^R(dis_x+dis_i-dis_{lca(i,x)}))
前面两项都可以直接计算/预处理得到。
后面这个东西 看似很难求 考虑 将所有i到根的路径上每一条边赋上权值 然后x向上爬路过的边如果存在权值 那么就是(dis_{lca(i,x)})了。
这个东西可以利用树链刨分进行快速赋值 而区间问题使用 可持久化线段树即可。
由于不能下传懒标记 所以需要标记永久化一下。
const int MAXN=60010;
int n,m,T,len,id,cnt;
int root[MAXN];
int f[MAXN],son[MAXN],dfn[MAXN],top[MAXN],pos[MAXN],d[MAXN],sz[MAXN];
ll dis[MAXN],sum[MAXN];
int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1],e[MAXN<<1];
struct wy
{
int l,r;
ll sum;
int s;
}t[MAXN*400];
inline void add(int x,int y,int z)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
e[len]=z;
}
inline void dfs(int x,int fa)
{
f[x]=fa;d[x]=d[fa]+1;sz[x]=1;
go(x)if(tn!=fa)
{
dis[tn]=dis[x]+e[i];
dfs(tn,x);
sz[x]+=sz[tn];
if(sz[tn]>sz[son[x]])son[x]=tn;
}
}
inline void dp(int x,int fa)
{
top[x]=fa;dfn[x]=++id;pos[id]=x;
if(son[x])dp(son[x],fa);
go(x)if(tn!=f[x]&&tn!=son[x])dp(tn,tn);
}
inline void insert(int &p,int las,int l,int r,int L,int R)
{
p=++cnt;t[p]=t[las];
if(L==l&&R==r){++s(p);return;}
sum(p)+=dis[pos[R]]-dis[f[pos[L]]];
int mid=(l+r)>>1;
if(R<=mid)insert(l(p),l(las),l,mid,L,R);
else
{
if(L>mid)insert(r(p),r(las),mid+1,r,L,R);
else insert(l(p),l(las),l,mid,L,mid),insert(r(p),r(las),mid+1,r,mid+1,R);
}
}
inline ll ask(int p,int las,int l,int r,int L,int R)
{
if(l==L&&R==r)
{
//cout<<(s(p)-s(las))<<‘ ‘<<s(p)<<endl;
return sum(p)-sum(las)+(s(p)-s(las))*(dis[pos[R]]-dis[f[pos[L]]]);
}
int mid=(l+r)>>1;
ll cnt=(s(p)-s(las))*(dis[pos[R]]-dis[f[pos[L]]]);
if(R<=mid)return cnt+ask(l(p),l(las),l,mid,L,R);
if(L>mid)return cnt+ask(r(p),r(las),mid+1,r,L,R);
return cnt+ask(l(p),l(las),l,mid,L,mid)+ask(r(p),r(las),mid+1,r,mid+1,R);
}
int main()
{
//freopen("1.in","r",stdin);
get(n);get(m);get(T);
rep(2,n,i)
{
int get(x),get(y),get(z);
add(x,y,z);add(y,x,z);
}
dfs(1,0);dp(1,1);
rep(1,n,i)sum[i]=sum[i-1]+dis[i];
rep(1,n,i)
{
int x=i;
while(top[x]!=1)
{
insert(root[i],root[i]?root[i]:root[i-1],1,n,dfn[top[x]],dfn[x]);
x=f[top[x]];
}
if(x!=1)insert(root[i],root[i]?root[i]:root[i-1],1,n,dfn[1]+1,dfn[x]);
}
ll ans=0;
rep(1,m,i)
{
int L,R,x;
get(L)^(ans*T);
get(R)^(ans*T);
get(x)^(ans*T);
ans=dis[x]*(R-L+1)+sum[R]-sum[L-1];
while(top[x]!=1)
{
ans-=2*ask(root[R],root[L-1],1,n,dfn[top[x]],dfn[x]);
//cout<<ask(root[R],root[L-1],1,n,dfn[top[x]],dfn[x])<<endl;
x=f[top[x]];
}
if(x!=1)ans-=2*ask(root[R],root[L-1],1,n,dfn[1]+1,dfn[x]);
putl(ans);ans%=n;
}
return 0;
}
以上是关于一本通 高手训练 1763 简单树 可持久化线段树 树链刨分 标记永久化的主要内容,如果未能解决你的问题,请参考以下文章