AtCoder Beginner Contest 337 G. Tree Inversion(dfs序+树状数组+树上差分 补写法)

题目

n(n<=2e5)个点的无根树,

定义f(u)为满足v<w且w在u到v的路径上的(v,w)的的数量,允许w和u重合或者w和v重合

输出f(1),f(2),...,f(n)的值

思路来源

乱搞ac

题解

赛中直接写了启发式合并过了,

属于是忽略了dfs序可以前缀作差的性质

如果按dfs序建主席树的话,感觉可作差的性质会直观很多

其实这个思路之前做17北航多校hdu6035的时候有用到过,

2017 Chinese Multi-University Training 1(C(树形dp)+F(置换群循环节)+H(nth_element)+I(仙人掌第k大生成树)+L(组合数学+dfs))_102253i - i curse myself-CSDN博客

进入子树时查询一个值,离开子树时查询一个值,

二者作差即为子树内的增量

其实就是枚举w,考虑w对哪些位置有贡献,w是子树树根枚举到的

子树内<w的值x,x到w的路径上直连儿子是v,那么在v这棵子树以外打标记

w子树外<w的值x,那么在w这棵子树以内打标记

打标记即对应区间加,实际打差分标记,左加又减

代码1(dfs序+树状数组)

#include<bits/stdc++.h>
#include<vector>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define scll(a) scanf("%lld",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
const int N=2e5+10;
int n,u,v,st[N],ed[N],dfn[N],c;
ll sum[N],ans[N];
vector<int>e[N];
struct BitPre{ // 求前缀和(可改为max等)
	int n,tr[N];
	void init(int _n){
		n=_n;
		memset(tr,0,(n+1)*sizeof(*tr));
	}
	void add(int x,int v){
		for(int i=x;i<=n;i+=i&-i)
		tr[i]+=v;
	}
	int sum(int x){
		int ans=0; 
		for(int i=x;i;i-=i&-i)
		ans+=tr[i];
		return ans;
	}
}tr;
void dfs(int u,int fa){
    tr.add(u,1);
    st[u]=++c;
    dfn[c]=u;
    int y1=tr.sum(u-1);
    for(auto &v:e[u]){
        if(v==fa)continue;
        int x1=tr.sum(u-1);
        dfs(v,u);
        int x2=tr.sum(u-1)-x1;
        sum[1]+=x2;
        sum[st[v]]-=x2;
        sum[ed[v]+1]+=x2;
    }
    ed[u]=c;
    int y2=tr.sum(u-1)-y1;
    int oth=u-1-y2;
    sum[st[u]]+=oth;
    sum[ed[u]+1]-=oth;
}
int main(){
    sci(n);
    tr.init(n);
    rep(i,2,n){
        sci(u),sci(v);
        e[u].pb(v);
        e[v].pb(u);
    }
    dfs(1,0);
    rep(i,1,n){
        sum[i]+=sum[i-1];
        ans[dfn[i]]=sum[i];
    }
    rep(i,1,n){
        printf("%lld%c",ans[i]," \n"[i==n]);
    }
    return 0;
}

代码2(启发式合并)

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define scll(a) scanf("%lld",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
const int N=2e5+10;
int n,u,v,st[N],ed[N],dfn[N],sz[N],c;
ll sum[N],ans[N];
vector<int>e[N];
unordered_map<int,int>now;
struct BitPre{ // 求前缀和(可改为max等)
	int n,tr[N];
	void init(int _n){
		n=_n;
		memset(tr,0,(n+1)*sizeof(*tr));
	}
	void add(int x,int v){
		for(int i=x;i<=n;i+=i&-i)
		tr[i]+=v;
	}
	int sum(int x){
		int ans=0; 
		for(int i=x;i;i-=i&-i)
		ans+=tr[i];
		return ans;
	}
}tr;
void dfs(int u,int fa){
    st[u]=++c;
    sz[u]=1;
    dfn[c]=u;
    for(auto &v:e[u]){
        if(v==fa)continue;
        dfs(v,u);
        sz[u]+=sz[v];
    }
    ed[u]=c;
}
void dfs(int u,int fa,bool keep){
    int mx=-1,son=-1;
    for(auto v:e[u]){
        if(v!=fa&&sz[v]>mx)
            mx=sz[v],son=v;
    }
    for(auto &v:e[u]){
        if(v!=fa&&v!=son){
            dfs(v,u,0);
        }
    }
    if(son!=-1){
        dfs(son,u,1);
        int z=tr.sum(u);
        sum[1]+=z;
        sum[st[son]]-=z;
        sum[ed[son]+1]+=z;
    }
    for(auto &v:e[u]){
        if(v!=fa&&v!=son){
            int z=0;
            for(int i=st[v];i<=ed[v];i++){
                int x=dfn[i];
                z+=(x<u);
                now[x]=1;
                tr.add(x,1);
            }
            sum[1]+=z;
            sum[st[v]]-=z;
            sum[ed[v]+1]+=z;
            // for(int i=st[v];i<=ed[v];i++){
            //     now[x]=1;
            //     tr.add(x,1);
            // }
        }
    }
    int z=tr.sum(u),oth=u-1-z;
    sum[st[u]]+=oth;
    sum[ed[u]+1]-=oth;
    // sum[1]+=z;
	// sum[st[u]+1]-=z;
	// sum[ed[u]+1]+=z; 
    now[u]=1;
    tr.add(u,1);
    if(keep==0){
        for(auto &x:now){
            tr.add(x.fi,-1);
        }
    	now.clear();
    }
}
int main(){
    sci(n);
    tr.init(n);
    rep(i,2,n){
        sci(u),sci(v);
        e[u].pb(v);
        e[v].pb(u);
    }
    dfs(1,0);
    dfs(1,0,0);
    rep(i,1,n){
        sum[i]+=sum[i-1];
        ans[dfn[i]]=sum[i];
    }
    rep(i,1,n){
        printf("%lld%c",ans[i]," \n"[i==n]);
    }
    return 0;
}

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
代码,好长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值