BZOJ3435: [Wc2014]紫荆花之恋 动态树分治 替罪羊树

再不写博客就快忘了这题怎么做了*1
题意:一棵树,点有点权r,边有边权c,每次增加一个叶子后询问当前有多少点对满足dis(i,j)≤ ri+rj,强制在线
N<=100000
考虑树分治,设现在要统计路径经过k的所有点对,则条件变为dis(i,k)+dis(j,k)≤ri+rj,移项得dis(i,k)-ri≤rj-dis(j,k),则可以在每个节点中用treap记录所有的dis(i,k)-ri。
类比树分治中每一层统计完信息后枚举每个子树把两端点都在这个子树中的点对减掉,这里不仅要有一个treap记录自己的所有信息,还要有一个treap记录这个点所管辖的节点在其父亲中的信息,然后逐层统计时要除去之前统计过的那个儿子的贡献。
于是每增加一个节点,在点分树上从它一直跳到根,把经过的节点答案累加即可。
还有一个问题是这题中的节点是动态生成的,那么我们用替罪羊树维护点分树,每次把新增的节点接到父亲下面,如果树失去平衡就按替罪羊规则进行重构,也就是对那一部分重新进行一次点分治。
注意细节,精雕细琢一下即可。
代码:

#include<cstdio>
#include<deque>
#include<cmath>
#include<tr1/random>
using namespace std;
const int N=100001;
typedef long long i64_t;
int n;
i64_t ans=0;
int r[N];
namespace Treap
{
    namespace Random
    {
        tr1::uniform_int<size_t> rnd(0,0xffffffffu);
        tr1::mt19937 e(114514);
        inline size_t rand()
        {
            return rnd(e);
        }
    }
    struct node
    {
        static deque<void*> stk;
        node *l,*r;
        size_t m_size;
        size_t m_cnt;
        int value;
        int weight;
        node(int value):l(),r(),m_size(1),m_cnt(1),value(value),weight(Random::rand()){}
        inline size_t size()
        {
            return this?m_size:0;
        }
        inline void up()
        {
            m_size=l->size()+m_cnt+r->size();
        }
        inline void* operator new(size_t)
        {
            if(stk.size())
            {
                node *x=(node*)stk.back();stk.pop_back();
                if(x->l) stk.push_back(x->l);
                if(x->r) stk.push_back(x->r);
                return x;
            }
            static node *s,*t;
            if(s==t) s=(node*)malloc(sizeof(node)<<16),t=s+(1<<16);
            return s++;
        }
        inline void operator delete(void* x)
        {
            if(x) stk.push_back(x);
        }
    };
    deque<void*> node::stk;
    struct pair{node *left,*right;};
    bool try_to_split(node *x,int v,pair& ret)
    {
        if(!x)
        {
            ret.left=ret.right=0;
            return 1;
        }
        pair kore;
        if(v<x->value)
        {
            if(!try_to_split(x->l,v,kore))
            {
                ++x->m_size;
                return 0;
            }
            x->l=kore.right;x->up();
            ret.left=kore.left,ret.right=x;
            return 1;
        }
        if(v>x->value)
        {
            if(!try_to_split(x->r,v,kore))
            {
                ++x->m_size;
                return 0;
            }
            x->r=kore.left;x->up();
            ret.left=x,ret.right=kore.right;
            return 1;
        }
        ++x->m_cnt,++x->m_size;
        return 0;
    }
    size_t count_less(node *x,int v)
    {
        size_t ret=0;
        while(x)
        {
            if(v<=x->value) x=x->l;
            else
            {
                ret+=x->size()-x->r->size();
                x=x->r;
            }
        }
        return ret;
    }
    void treap_insert(node *&o,const node &x)
    {
        if(!o)
        {
            o=new node(x);
            return;
        }
        if(x.weight>o->weight)
        {
            pair kore;
            if(!try_to_split(o,x.value,kore)) return;
            o=new node(x);
            o->l=kore.left,o->r=kore.right;
            o->up();
            return;
        }
        ++o->m_size;
        if(x.value<o->value) treap_insert(o->l,x);
        else if(x.value>o->value) treap_insert(o->r,x);
        else ++o->m_cnt;
    }
    class tree
    {
        private:
            node *root;
        public:
            tree():root(){}
            inline void insert(int x)
            {
                treap_insert(root,node(x));
            }
            inline void clear()
            {
                delete root;
                root=0;
            }
            inline size_t order_of_key(int x)
            {
                return count_less(root,x);
            }
    };
}
namespace Graph
{
    struct edge_t
    {
        static deque<void*> stk;
        int to;
        int value;
        edge_t *nex;
        edge_t(int to,edge_t *nex,int value):to(to),nex(nex),value(value){}
        inline void* operator new(size_t)
        {
            if(stk.size())
            {
                edge_t *x=(edge_t*)stk.back();stk.pop_back();
                if(x->nex) stk.push_back(x->nex);
                return x;
            }
            static edge_t *s,*t;
            if(s==t) s=(edge_t*)malloc(sizeof(edge_t)<<16),t=s+(1<<16);
            return s++;
        }
        inline void operator delete(void *x)
        {
            if(x) stk.push_back(x);
        }
    };
    deque<void*> edge_t::stk;
    struct iterator
    {
        edge_t *ptr;
        iterator(edge_t *ptr=0):ptr(ptr){}
        int operator *() const
        {
            return ptr->to;
        }
        iterator& operator ++()
        {
            ptr=ptr->nex;
            return *this;
        }
        operator bool const()
        {
            return ptr;
        }
        inline int cost()
        {
            return ptr->value;
        }
    };
    class edge_list
    {
        private:
            iterator front[N];
        public:
            edge_list():front(){}
            inline void add_edge(int u,int v,int c=0)
            {
                front[u]=iterator(new edge_t(v,front[u].ptr,c));
            }
            inline void clear_edge(int u)
            {
                delete front[u].ptr;
                front[u].ptr=0;
            }
            inline iterator begin(int u)
            {
                return front[u];
            }
    };
}
namespace Numeric
{
    int fa[N][17];
    int dep[N];
    int len[N];
    int maxn;
    void push_back_at(int x,int y,int edge_v)
    {
        fa[y][0]=x;
        dep[y]=dep[x]+edge_v;
        len[y]=len[x]+1;
        if(!maxn) maxn=log2(n);
        for(int i=1;i<=maxn;++i)
        fa[y][i]=fa[fa[y][i-1]][i-1];
    }
    int LCA(int a,int b)
    {
        if(len[a]<len[b]) swap(a,b);
        size_t __dis=len[a]-len[b];
        size_t cnt=0;
        while(__dis)
        {
            if(__dis&1u) a=fa[a][cnt];
            __dis>>=1;
            ++cnt;
        }
        if(a==b) return a;
        for(int i=maxn;~i;--i)
        {
            if(fa[a][i]!=fa[b][i])
            a=fa[a][i],b=fa[b][i];
        }
        return fa[a][0];
    }
    inline int distance(int a,int b)
    {
        return dep[a]+dep[b]-(dep[LCA(a,b)]<<1);
    }
}
namespace Divide_and_Conquer
{
    using Treap::tree;
    using Graph::edge_list;
    using Numeric::distance;
    tree self[N],tofat[N];
    edge_list origin,scape;
    size_t __clock=0;
    size_t ban[N],vis[N];
    int fa[N],size[N];
    int center(int x,int &_size,int limit,int from)
    {
        _size=1;
        int nsize;
        bool is_this=1;
        for(Graph::iterator i=origin.begin(x);i;++i)
        {
            if(ban[*i]==__clock||vis[*i]!=__clock||*i==from) continue;
            int ret=center(*i,nsize,limit,x);
            if(ret!=-1) return ret;
            if(nsize>limit>>1) is_this=0;
            _size+=nsize;
        }
        if(limit-_size>limit>>1) is_this=0;
        return is_this?x:-1;
    }
    int traversal(int x,int dep,int from,tree &set)
    {
        set.insert(dep-r[x]);
        int ret=1;
        for(Graph::iterator i=origin.begin(x);i;++i)
        {
            if(ban[*i]==__clock||vis[*i]!=__clock||*i==from) continue;
            ret+=traversal(*i,dep+i.cost(),x,set);
        }
        return ret;
    }
    #define null_from (-1)
    void solve(int x)
    {
        ban[x]=__clock;
        size[x]=traversal(x,0,null_from,self[x]);
        for(Graph::iterator i=origin.begin(x);i;++i)
        {
            if(ban[*i]==__clock||vis[*i]!=__clock) continue;
            tree temp;
            int _size=traversal(*i,i.cost(),x,temp);
            int y=center(*i,_size,_size,x);
            tofat[y]=temp;fa[y]=x;
            scape.add_edge(x,y);
            solve(y);
        }
    }
    void clear(int x)
    {
        vis[x]=__clock;
        for(Graph::iterator i=scape.begin(x);i;++i)
        {
            if(fa[*i]==x)
            clear(*i);
        }
        scape.clear_edge(x);
        self[x].clear();tofat[x].clear();
    }
    void reincarnation(int x)
    {
        vis[x]=++__clock;
        tree temp=tofat[x];
        self[x].clear();
        for(Graph::iterator i=scape.begin(x);i;++i)
        {
            if(fa[*i]==x)
            clear(*i);
        }
        scape.clear_edge(x);
        int _size=size[x];
        int _fa=fa[x];
        x=center(x,_size,_size,null_from);
        tofat[x]=temp;fa[x]=_fa;scape.add_edge(fa[x],x);
        solve(x);
    }
    i64_t push_back_at(int x,int y,int c)
    {
        Numeric::push_back_at(x,y,c);
        origin.add_edge(x,y,c);
        origin.add_edge(y,x,c);
        scape.add_edge(x,y);
        fa[y]=x,size[y]=1;
        self[y].insert(-r[y]);
        for(int i=y;fa[i];i=fa[i])
        {
            x=fa[i];
            int __dis=distance(x,y);
            ans+=self[x].order_of_key(r[y]-__dis+1)-tofat[i].order_of_key(r[y]-__dis+1);
            ++size[x];
            self[x].insert(__dis-r[y]),tofat[i].insert(__dis-r[y]);
        }
        for(int i=y;fa[i];i=fa[i])
        {
            double limit=size[fa[i]]*0.7;
            if(size[i]>limit)
            {
                reincarnation(fa[i]);
                break;
            }
        }
        return ans;
    }
}
namespace FastIO
{
    const size_t str=1<<16;
    struct Reader
    {
        char buf[str],*s,*t;
        Reader():s(),t(),buf(){}
        inline char pick()
        {
            return (s==t)?(t=buf+fread(s=buf,1,str,stdin),*s++):(*s++);
        }
        Reader& operator >> (int &x)
        {
            register char c;
            do c=pick(); while(c<'0'||c>'9');
            x=0;
            while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=pick();
            return *this;
        }
    }cin;
    struct Writer
    {
        char buf[str],*s,*t;
        Writer():s(buf),t(buf+str),buf(){}
        ~Writer(){fwrite(buf,1,s-buf,stdout);}
        inline void echo(char c)
        {
            (s==t)?(fwrite(s=buf,1,str,stdout),*s++=c):(*s++=c);
        }
        Writer& operator << (i64_t x)
        {
            if(!x) return echo('0'),*this;
            register char a[21],t=1;
            while(x) a[t++]=x%10,x/=10;
            while(--t) echo(a[t]+'0');
            return *this;
        }
        Writer& operator << (const char* s)
        {
            while(*s) echo(*s++);
            return *this;
        }
    }cout;
    const char *endl="\n";
}
using FastIO::cin;
using FastIO::cout;
using FastIO::endl;
int main()
{
    cin>>n>>n;
    for(int i=1;i<=n;++i)
    {
        int ai,bi;
        cin>>ai>>bi>>r[i];
        ai^=int(ans%1000000000);
        cout<<Divide_and_Conquer::push_back_at(ai,i,bi)<<endl;;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值