hnoi的大数据结构题
把每一个残基缩一下 变成一颗大树
每次新增
查询一下是在哪个残基上 这里要用主席树求子树第k大
然后记一下到fat的权值
然后就各种细节搞lca
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
inline void read(ll &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=100005;
#define V G[p].v
namespace tree1{
struct edge{
int u,v,next;
}G[N<<2];
int head[N],inum;
inline void add(int u,int v,int p){
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
inline void link(int u,int v){
add(u,v,++inum); add(v,u,++inum);
}
const int K=21;
int fat[N][K],depth[N];
int clk,pre[N],bac[N],size[N];
inline void dfs(int u,int fa){
pre[u]=++clk; bac[clk]=u; size[u]=1;
fat[u][0]=fa; depth[u]=depth[fa]+1;
for (int k=1;k<K;k++) fat[u][k]=fat[fat[u][k-1]][k-1];
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
dfs(V,u),size[u]+=size[V];
}
inline int LCA(int u,int v){
if (depth[u]<depth[v]) swap(u,v);
for (int k=K-1;~k;k--)
if ((depth[u]-depth[v])&(1<<k))
u=fat[u][k];
if (u==v) return u;
for (int k=K-1;~k;k--)
if (fat[u][k]!=fat[v][k])
u=fat[u][k],v=fat[v][k];
return fat[v][0];
}
inline int Dist(int u,int v){
return depth[u]+depth[v]-2*depth[LCA(u,v)];
}
}
namespace tree2{
struct edge{
int u,v,w,next;
}G[N<<2];
int head[N],inum;
inline void add(int u,int v,int w,int p){
G[p].u=u; G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;
}
inline void link(int u,int v,int w){
add(u,v,w,++inum); add(v,u,w,++inum);
}
const int K=21;
int fat[N][K],depth[N]; ll dis[N];
int clk,pre[N],bac[N],size[N];
inline void dfs(int u,int fa){
pre[u]=++clk; bac[clk]=u; size[u]=1;
fat[u][0]=fa; depth[u]=depth[fa]+1;
for (int k=1;k<K;k++) fat[u][k]=fat[fat[u][k-1]][k-1];
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
dis[V]=dis[u]+G[p].w,dfs(V,u),size[u]+=size[V];
}
inline int LCA(int u,int v){
if (depth[u]<depth[v]) swap(u,v);
for (int k=K-1;~k;k--)
if ((depth[u]-depth[v])&(1<<k))
u=fat[u][k];
if (u==v) return u;
for (int k=K-1;~k;k--)
if (fat[u][k]!=fat[v][k])
u=fat[u][k],v=fat[v][k];
return fat[v][0];
}
inline int Fat(int u,int lca){
for (int k=K-1;~k;k--)
if (depth[fat[u][k]]>depth[lca])
u=fat[u][k];
return u;
}
inline ll Dist(int u,int v){
return dis[u]+dis[v]-2*dis[LCA(u,v)];
}
}
namespace Seg{
int root[N],ncnt;
int ls[N*21],rs[N*21],sum[N*21];
inline void Add(int &x,int y,int l,int r,int t){
if (!x) x=++ncnt; int mid=(l+r)>>1;
if (l==r){
sum[x]=sum[y]+1;
return;
}
if (t<=mid)
Add(ls[x],ls[y],l,mid,t),rs[x]=rs[y];
else
Add(rs[x],rs[y],mid+1,r,t),ls[x]=ls[y];
sum[x]=sum[ls[x]]+sum[rs[x]];
}
inline int Query(int x,int y,int l,int r,int k){
if (l==r) return l; int mid=(l+r)>>1;
if (k<=sum[ls[y]]-sum[ls[x]])
return Query(ls[x],ls[y],l,mid,k);
else
return Query(rs[x],rs[y],mid+1,r,k-(sum[ls[y]]-sum[ls[x]]));
}
}
int n,m,Q;
inline void Init(){
using namespace tree1;
for (int i=1;i<=n;i++)
Seg::Add(Seg::root[i],Seg::root[i-1],1,n,bac[i]);
}
inline int Query(int u,int k){
using namespace tree1;
return Seg::Query(Seg::root[pre[u]-1],Seg::root[pre[u]+size[u]-1],1,n,k);
}
int fcnt,ft[N],ff[N];
ll fl[N],fr[N];
inline int belong(ll idx){
return lower_bound(fr+1,fr+fcnt+1,idx)-fr;
}
inline void Link(int a,ll b){
int rt=belong(b);
int ch=Query(ft[rt],b-fl[rt]+1);
++fcnt; ft[fcnt]=a; fl[fcnt]=fr[fcnt-1]+1; fr[fcnt]=fr[fcnt-1]+tree1::size[a]; ff[fcnt]=ch;
tree2::link(rt,fcnt,tree1::depth[ch]-tree1::depth[ft[rt]]+1);
}
inline ll Dis(ll u){
int rt=belong(u);
int ch=Query(ft[rt],u-fl[rt]+1);
return tree2::dis[rt]+tree1::depth[ch]-tree1::depth[ft[rt]];
}
inline void Solve(ll a,ll b){
ll ret=Dis(a)+Dis(b),tem=0;
int rta=belong(a),rtb=belong(b),lca=tree2::LCA(rta,rtb);
if (lca==rta && lca==rtb){
int cha=Query(ft[rta],a-fl[rta]+1),chb=Query(ft[rtb],b-fl[rtb]+1);
int t=tree1::LCA(cha,chb);
tem+=tree2::dis[lca];
tem+=tree1::depth[t]-tree1::depth[ft[lca]];
}
else if (lca==rta || lca==rtb){
if (rtb==lca) swap(rtb,rta),swap(a,b);
int cha=Query(ft[rta],a-fl[rta]+1),chb=tree2::Fat(rtb,lca);
int t=tree1::LCA(cha,ff[chb]);
tem+=tree2::dis[lca];
tem+=tree1::depth[t]-tree1::depth[ft[lca]];
}else{
int cha=tree2::Fat(rta,lca),chb=tree2::Fat(rtb,lca);
int t=tree1::LCA(ff[cha],ff[chb]);
tem+=tree2::dis[lca];
tem+=tree1::depth[t]-tree1::depth[ft[lca]];
}
printf("%lld\n",ret-2*tem);
}
int main(){
int iu,iv; ll ia,ib;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); read(m); read(Q);
for (int i=1;i<n;i++){
read(iu); read(iv);
tree1::link(iu,iv);
}
tree1::dfs(1,0);
Init();
fcnt=1; fl[1]=1; fr[1]=n; ft[1]=1;
for (int i=1;i<=m;i++){
read(iu); read(ib);
Link(iu,ib);
}
tree2::dfs(1,0);
while (Q--){
read(ia); read(ib);
Solve(ia,ib);
}
return 0;
}