CSU 1811 Tree Intersection(平衡树的子树合并)

题意:对于每一条边,去掉一条边后,生成两颗树,问这两颗树的交集大小。

分析:1、O(n^2)算法:每次都用O(n)的时间去合并两个区间,因此可以从合并这个地方去优化。

        2、可以这么考虑,在遍历树的时候计算去掉的两树的交集,那么每次我们只要把当前点的所有子树合并便可得到当前点的父边的解。

        3、具体实现细节代码见。

复杂度是O(nlog^2n),具体可以参考大白p234那一道题。

吐槽:手挫,思路一早就有了,就代码一直写得….

/************************************************
Author        :DarkTong
Created Time  :2016/9/5 21:20:03
File Name     :Hulan_I.cpp
*************************************************/

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const int maxn = 200000 + 100;
#define MIN 0x80000000
#define MAX 0x7fffffff
int vis[maxn];
struct Splay_Tree
{
    int ch[maxn][2], r[maxn], val[maxn], s[maxn], cnt[maxn];
    queue<int> ssz;
    void init(){
        while(!ssz.empty()) ssz.pop();
        for(int i=1;i<maxn;++i) ssz.push(i);
    }
    int newNode(int vv=0){
        int sz = ssz.front(); ssz.pop();
        ch[sz][0]=ch[sz][1]=0, s[sz]=1;
        val[sz]=vv; r[sz]=rand(); 
        cnt[sz]=0;
        return sz;
    }
    //比较函数
    int cmp(int v, int x){
        if(x==v) return -1;
        else return x < v ? 0 : 1;
    }
    //更新s[]
    void maintain(int o){
        s[o] = s[ch[o][0]]+s[ch[o][1]]+1;    
    }
    //旋转操作
    void rotate(int &o, int d){
        int k=ch[o][d^1]; ch[o][d^1]=ch[k][d]; ch[k][d]=o;
        maintain(o);// maintain(k); 
        o=k;
    }
    void insert(int &o, int x, int cn, int &ans){
        if(!o) {
            o=newNode(x);
            cnt[o] = cn;
            if(cn<vis[x]) ++ans;
        }else{
            int d = cmp(val[o], x);    //若有相同值,则不能使用cmp()函数
            if(d!=-1)
            {
                insert(ch[o][d], x, cn, ans);
                if(r[ch[o][d]] > r[o]) rotate(o, d^1);
            }
            else
            {
                cnt[o]+=cn;
                if(cnt[o]==vis[x]) --ans;
            }
        }
        maintain(o);
    }
    void mergeto(int &src, int &dest, int &ans)
    {
        if(ch[src][0]) mergeto(ch[src][0], dest, ans);
        if(ch[src][1]) mergeto(ch[src][1], dest, ans);
        ssz.push(src);
        insert(dest, val[src], cnt[src], ans);
        src = 0;
    }
}slt;


vector<int> G[maxn];
int ans[maxn], val[maxn], n, ha[maxn];
map<pair<int, int>, int> id;
int dfs(int u, int fa)
{
    int tmp, sam = 0;
    slt.insert(ha[u], val[u], 1, sam);
    for(int i=0;i<G[u].size();++i)
    {
        int v = G[u][i];
        if(v==fa) continue;
        int tsam = dfs(v, u);

        if(slt.s[ha[v]] > slt.s[ha[u]])
        {
            swap(ha[u], ha[v]);
            sam = tsam;
        }
        if(ha[v]) slt.mergeto(ha[v], ha[u], sam);
    }
    ans[id[make_pair(min(u, fa), max(u, fa))]] = sam;
    return sam;
}

int main()
{
    int T, cas=1;
    while(scanf("%d", &n)==1)
    {
        memset(vis, 0, sizeof(vis));
        memset(ans, 0, sizeof(ans));
        memset(ha, 0, sizeof(ha));
        slt.init();
        for(int i=1;i<maxn;++i)  G[i].clear();
        id.clear();

        int u, v;
        for(int i=1;i<=n;++i) scanf("%d", &val[i]), vis[val[i]]++;
        for(int i=1;i<n;++i)
        {
            scanf("%d%d", &u, &v);
            if(u>v) swap(u, v);
            id[make_pair(u, v)] = i;
            G[u].push_back(v);
            G[v].push_back(u);
        }
        id[make_pair(0, 1)] = 0;
        dfs(1, 0);
        for(int i=1;i<n;++i)
        {
            printf("%d\n", ans[i]);
        }
    }
    
    return 0;
}

转载于:https://www.cnblogs.com/DarkTong/p/5847299.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值