大意:树上单边修改,查询路径长。
树链剖分,边剖即可。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <queue>
#define ll long long
#define inf 0x7fffffff
#define N 300009
using namespace std;
int n,m,number=0,cnt=0,first[N],father[N],top[N],dfn[N],size[N],Mson[N];
int sum[N*10],deep[N],ed[N];
struct edge
{
int to,next;
void add(int x,int y)
{
to=y,next=first[x],first[x]=number;
}
}e[2*N];
void dfs1(int x)
{
size[x]=1;
deep[x]=deep[father[x]]+1;
for (int i=first[x];i;i=e[i].next)
if (e[i].to!=father[x])
{
father[e[i].to]=x;
dfs1(e[i].to);
size[x]+=size[e[i].to];
if (size[e[i].to]>size[Mson[x]])
Mson[x]=e[i].to;
}
}
void dfs2(int x,int y)
{
dfn[x]=++cnt;
top[x]=y;
if (Mson[x]) dfs2(Mson[x],y);
for (int i=first[x];i;i=e[i].next)
if (e[i].to!=father[x]&&e[i].to!=Mson[x])
dfs2(e[i].to,e[i].to);
ed[x]=cnt;
}
void ins(int l,int r,int x,int k,int y)
{
if (l==r)
{
sum[k]=y;
return;
}
int mid=l+r>>1;
if (x<=mid) ins(l,mid,x,k<<1,y);
else ins(mid+1,r,x,k<<1|1,y);
sum[k]=sum[k<<1]+sum[k<<1|1];
}
int qry(int l,int r,int L,int R,int k)
{
if (L>R) return 0;
if (L<=l&&R>=r) return sum[k];
int mid=l+r>>1;
int ans=0;
if (L<=mid) ans+=qry(l,mid,L,R,k<<1);
if (R>mid) ans+=qry(mid+1,r,L,R,k<<1|1);
return ans;
}
int Qry(int x,int y)
{
int ans=0;
for (;top[x]!=top[y];x=father[top[x]])
{
if (deep[top[x]]<deep[top[y]]) swap(x,y);
ans+=qry(2,n,dfn[top[x]],dfn[x],1);
}
if (dfn[y]>dfn[x]) swap(x,y);
ans+=qry(2,n,dfn[y]+1,dfn[x],1);
return ans;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
e[++number].add(x,y);
e[++number].add(y,x);
}
dfs1(1);
dfs2(1,1);
scanf("%d",&m);
for (int i=2;i<=n;i++)
ins(2,n,dfn[i],1,1);
for (int i=1;i<=n+m-1;i++)
{
char ch;
int x,y;
while (ch=getchar(),ch!='W'&&ch!='A');
scanf("%d",&x);
if (ch=='W')
{
printf("%d\n",Qry(1,x));
continue;
}
scanf("%d",&y);
if (x<y) swap(x,y);
ins(2,n,dfn[x],1,0);
}
}//%lych %miaom

本文详细介绍了一种高效的树链剖分算法,该算法适用于树形结构上的单边修改及路径查询问题。通过树链剖分,可以将复杂的问题转换为简单的区间更新和查询操作,极大提高了处理效率。
744

被折叠的 条评论
为什么被折叠?



