码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2016-09-06 23:03:32      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:

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

分析: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;
}

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

标签:

原文地址:http://www.cnblogs.com/DarkTong/p/5847299.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!