• 【WOJ3936】路径的交(dfs序+树状数组+Lca)


    描述
    给定一棵n个点的树 一下给出m条路径(以u-v形式) 第i条路径要求询问前i-1条与他有多少相交的(点相交即为相交)
    输入
    第一行一个正整数n表示节点个数。接下来n-1行,每行两个正整数分别是u,v表示节点u和v之间有连边。接下来一行一个 正整数m表示路径个数。然后有m行,每行两个正整数分别是u,v分别表示u到v之间有一条路径。
    输出
    输出共m行,每行一个整数,第i行表示豪哥在这条路径上获得的交往机会。
    样例输入
    5
    1 2
    1 3
    3 4
    3 5
    4
    4 5
    4 2
    1 3
    1 2
    样例输出
    0
    1
    2
    2
    提示
    对于100%的数据n,m≤200000

    考虑到可能会有2种相交的情况:


    1.一条路径的lcalca在另一条上:
    。
    对于这种情况我们显然是要统计路径上有多少个lcalca
    当然可以用树剖每次O(log2n)O(log^2n)统计
    但我们考虑一种更优的做法
    我们对每个点维护一个sumsum表示它到根上有多少个lcalca
    那么ans1=sumu+sumvsumlcasumfalcaans_1=sum_u+sum_v-sum_{lca}-sum_{fa_{lca}}
    显然对于每个lcalca只会对其子树产生+11的贡献
    那在dfsdfs序上区间修改单点查询(可以用差分树状数组变成单点修改区间查询)


    2.一条路径的lcalca不在另一条上(一条路径直接穿过了另一条):

    在这里插入图片描述
    那我们考虑差分:

    uvu、v处分别+11,lcalca2-2,那答案就是lcalca的子树和了(想想为什么)

    那树状数组单点修改区间查询就可以了

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	char ch=getchar();
    	int res=0,f=1;
    	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    	return res*f;
    }
    const int N=200005;
    int tr1[N],n,m,tr2[N],pos[N],tot,dep[N],siz[N],fa[N],son[N],top[N],adj[N],nxt[N<<1],to[N<<1],cnt;
    inline int lowbit(int x){
    	return (x&(-x));
    }
    inline void addedge(int u,int v){
    	nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
    }
    void dfs(int u){
    	siz[u]=1,pos[u]=++tot;
    	for(int e=adj[u];e;e=nxt[e]){
    		int v=to[e];
    		if(v==fa[u])continue;
    		dep[v]=dep[u]+1,fa[v]=u;
    		dfs(v),siz[u]+=siz[v];
    		if(siz[v]>siz[son[u]])son[u]=v;
    	}
    }
    void dfs2(int u,int tp){
    	top[u]=tp;
    	if(!son[u])return;
    	dfs2(son[u],tp);
    	for(int e=adj[u];e;e=nxt[e]){
    		int v=to[e];
    		if(v==fa[u]||v==son[u])continue;
    		dfs2(v,v);
    	}
    }
    inline int Lca(int u,int v){
    	while(top[u]!=top[v]){
    		if(dep[top[u]]<dep[top[v]])v=fa[top[v]];
    		else u=fa[top[u]];
    	}
    	return dep[u]<dep[v]?u:v;
    }
    inline void update(int *tr,int pos,int k){
    	for(;pos<=n;pos+=lowbit(pos))tr[pos]+=k;
    }
    inline int query(int *tr,int pos,int res=0){
    	for(;pos;pos-=lowbit(pos))res+=tr[pos];return res;
    }
    int main(){
    	n=read();
    	for(int i=1;i<n;i++){
    		int u=read(),v=read();
    		addedge(u,v),addedge(v,u);
    	}
    	dfs(1),dfs2(1,1);
    	m=read();
    	for(int i=1;i<=m;i++){
    		int u=read(),v=read(),ans=0;
    		int lca=Lca(u,v);
    		ans+=query(tr1,pos[u])+query(tr1,pos[v])-query(tr1,pos[lca])-query(tr1,pos[fa[lca]]);
    		ans+=query(tr2,pos[lca]+siz[lca]-1)-query(tr2,pos[lca]-1); 
    		update(tr1,pos[lca],1),update(tr1,pos[lca]+siz[lca],-1);
    		update(tr2,pos[u],1),update(tr2,pos[v],1),update(tr2,pos[lca],-2);
    		cout<<ans<<'
    ';
    	}
    }
    
  • 相关阅读:
    响应式css样式
    组件 computed 与 vuex 中 getters 的使用,及 mapGetters 的使用,对象上追加属性,合并对象
    nginx 错误集锦
    动态的添加路由
    NProgress的使用 及 路由 token 定向的使用
    token的解码及 判断值不为空的方法
    nginx 的使用
    IT公司100题-tencent-打印所有高度为2的路径
    测试
    Objective-C 与 C++ 的异同
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/10366315.html
Copyright © 2020-2023  润新知