题目大意
%
给定一棵
n
n
n 个点的树,给定树上的
P
P
P 条链,求有多少个无序数对
(
u
,
v
)
(u,v)
(u,v) 满足第
u
u
u 条链和第
v
v
v 条链有交点。
数据范围
1
⩽
n
,
P
⩽
1
0
6
1\leqslant n,P\leqslant 10^6
1⩽n,P⩽106
题解
% 我们考虑每次加入一条链子,计算有多少条链和这条链有交点。在插入一条链的时候,给链上的点权加一 ,链上的边权减一,询问的时候就等价于一个链上求和(包括边上的和点上的)。
代码
#include<bits/stdc++.h>
using namespace std;
//两种合并后的线段树
struct node{
int l,r,d,lazy;
bool nodes;
node *left,*right;
node(int tl,int tr,bool tnodes):left(NULL),right(NULL),l(tl),r(tr),d(0),lazy(0),nodes(tnodes){
if(tnodes) if(tl==tr) return;
if(!tnodes) if(tl+1==tr) return;
int mid=(tl+tr)>>1;
left=new node(tl,mid,nodes);
right=new node(mid+tnodes,tr,tnodes);
}
void update(){
if(lazy&&left){
left->lazy+=lazy;
right->lazy+=lazy;
left->d+=(left->r-left->l+nodes)*lazy;
right->d+=(right->r-right->l+nodes)*lazy;
}lazy=0;
}
void add(int tl,int tr,int td){
if(l==tl&&r==tr){
lazy+=td;
d+=(r-l+nodes)*td;
return;
} update();
if(tr<=left->r) left->add(tl,tr,td);
else if(tl>=right->l) right->add(tl,tr,td);
else left->add(tl,left->r,td),right->add(right->l,tr,td);
d=left->d+right->d;
}
int sum(int tl,int tr){
if(l==tl&&r==tr) return d;
update();
if(tr<=left->r) return left->sum(tl,tr);
if(tl>=right->l) return right->sum(tl,tr);
return left->sum(tl,left->r)+right->sum(right->l,tr);
}
};
#define maxn 1000010
struct edge{
int v,next;
}edges[maxn];
int n,head[maxn];
void ins(int u,int v){
static int cnt=0;
edges[++cnt]=(edge){v,head[u]};
head[u]=cnt;
}
int fa[maxn],dep[maxn],size[maxn],son[maxn];
void predfs(int u){
size[u]=1;
for(int i=head[u];i;i=edges[i].next){
int v=edges[i].v;
if(v==fa[u]) continue;
fa[v]=u;dep[v]=dep[u]+1;
predfs(v); size[u]+=size[v];
if(size[son[u]]<size[v]) son[u]=v;
}
}
int top[maxn],code[maxn],init[maxn];
void recode(int u,int chain){
static int cnt=0;
top[init[code[u]=++cnt]=u]=chain;
if(son[u]) recode(son[u],chain);
for(int i=head[u];i;i=edges[i].next){
int v=edges[i].v;
if(v==fa[u]||v==son[u]) continue;
recode(v,v);
}
}
node *E,*V;
void add_node(int x,int y,int d){
int tx=top[x],ty=top[y];
while(tx!=ty){
if(dep[tx]<dep[ty]) swap(x,y),swap(tx,ty);
V->add(code[tx],code[x],d);
x=fa[tx],tx=top[x];
} if(code[x]>code[y]) swap(x,y);
V->add(code[x],code[y],d);
}
int sum_node(int x,int y){
int tx=top[x],ty=top[y];
int ans=0;
while(tx!=ty){
if(dep[tx]<dep[ty]) swap(x,y),swap(tx,ty);
ans+=V->sum(code[tx],code[x]);
x=fa[tx],tx=top[x];
} if(code[x]>code[y]) swap(x,y);
return ans+V->sum(code[x],code[y]);
}
int W[maxn];
void add_edge(int x,int y,int d){
int tx=top[x],ty=top[y];
while(tx!=ty){
if(dep[tx]<dep[ty]) swap(x,y),swap(tx,ty);
if(code[tx]!=code[x]) E->add(code[tx],code[x],d);
W[tx]+=d;
x=fa[tx],tx=top[x];
} if(code[x]>code[y]) swap(x,y);
if(code[x]!=code[y]) E->add(code[x],code[y],d);
}
int sum_edge(int x,int y){
int tx=top[x],ty=top[y];
int ans=0;
while(tx!=ty){
if(dep[tx]<dep[ty]) swap(x,y),swap(tx,ty);
if(code[tx]!=code[x]) ans+=E->sum(code[tx],code[x]);
ans+=W[tx];
x=fa[tx],tx=top[x];
} if(code[x]>code[y]) swap(x,y);
if(code[x]!=code[y]) ans+=E->sum(code[x],code[y]);
return ans;
}
int add_link(int u,int v){
add_node(u,v,1);
add_edge(u,v,-1);
}
int sum_link(int u,int v){
return sum_node(u,v)+sum_edge(u,v);
}
int main(){
int m; scanf("%d%d",&n,&m);
for(int i=1,a,b;i<n;i++){
scanf("%d%d",&a,&b);
ins(a,b);ins(b,a);
} predfs(2);recode(2,2);
E=new node(1,n,false);
V=new node(1,n,true);
long long cnt=0;
for(int i=1,a,b;i<=m;i++){
scanf("%d%d",&a,&b);
cnt+=sum_link(a,b);
add_link(a,b);
} printf("%lld\n",cnt);
return 0;
}