bzoj 3435 紫荆花之恋 动态树分治+替罪羊+treap

我从未见过如此恶心的树分治。。。。

先动态维护这个树的树分治,当一个子树大小太大时,重构这个点和他的所有子树,用树分治分成平均的子树。

对于一个插入和查询,在树分治结构中从深度高到深度低遍历。然后统计新插入的点过当前中心,到当前分治结构中的路径。
对于一条从 x y 过当前分治中心的路径,设点 x 距当前分治中心的路径长度为 dis(x) 。那么需要满足的条件就是 dis[x]+dis[y]<=r[x]+r[y]
dis[y]r[y]<=r[x]dis[x]

那么对于每个分治中心维护一个平衡树存 dis[x]r[x] ,对于分治中心的子节点维护存h子树中 dis[x]r[x] 的平衡树。查询时答案加当前分治中心的平衡树中 dis[y]r[y]<=r[x]dis[x] 的y的个数减当前分治中心有x的子树的平衡树的中 dis[y]r[y]<=r[x]dis[x] 的y的个数。并将这个点插入。

不知道为什么在bz上是TLE的,可能是我写的太挫。

#include <bits/stdc++.h>
using namespace std;
#define N 110000
#define M 15000000
#define ls ch[x][0]
#define rs ch[x][1]
#define ll long long
#define D 51
#define which(x) ch[fa[x]][1]==x
int n,top,r[N];
pair<int,int>st[N];
ll ans;
struct fastio
{
    char getc()
    {
        static const int LEN = 4096;
        static char buf[LEN],*S=buf,*T=buf;
        if(S == T)
        {
            T = (S=buf)+fread(buf,1,LEN,stdin);
            if(S == T)return EOF;
        }
        return *S++;
    }
    int read()
    {
        static char ch;
        static int d;
        while(!isdigit(ch=getc()));
        for(d=ch-'0'; isdigit(ch=getc());)
            d=(d<<3)+(d<<1)+(ch-'0');
        return d;
    }       
}io;
struct graph
{
    int head[N],nex[N<<1],to[N<<1],val[N<<1],tot;
    int fa[N][21],d[N],deep[N];
    void add(int x,int y,int z)
    {
        if(!x||!y)return;
        nex[++tot]=head[x];head[x]=tot;
        to[tot]=y;val[tot]=z;
        if(x>y)
        {
            deep[x]=deep[y]+1;
            fa[x][0]=y;d[x]=d[y]+z;
            for(int i=1;i<=20;i++)
                fa[x][i]=fa[fa[x][i-1]][i-1];
        }
    }
    int lca(int x,int y)
    {
        if(deep[x]<deep[y])swap(x,y);
        for(int i=20;i>=0;i--)
            if(deep[fa[x][i]]>=deep[y])x=fa[x][i];
        if(x==y)return x;
        for(int i=20;i>=0;i--)
            if(fa[x][i]!=fa[y][i])
                x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    int dis(int x,int y)
    {return d[x]+d[y]-2*d[lca(x,y)];}
}g;
struct treap
{
    int ch[M][2],val[M],rnd[M],size[M],fa[M],cnt;
    queue<int>que;
    int ap()
    {
        if(que.empty())return ++cnt;
        int x=que.front();que.pop();
        ls=rs=0;val[x]=0;rnd[x]=0;size[x]=0;fa[x]=0;
        return x;
    }
    void pushup(int x)
    {size[x]=size[ls]+size[rs]+1;}
    int rotate(int x)
    {
        int y=fa[x],k=which(x);

        ch[y][k]=ch[x][k^1];
        ch[x][k^1]=y;
        ch[fa[y]][which(y)]=x;

        fa[x]=fa[y];fa[y]=x;
        fa[ch[y][k]]=y;

        pushup(y);pushup(x);
        return x;
    }
    int insert(int x,int v)
    {   
        if(!x)
        {
            size[x=ap()]=1;
            val[x]=v;rnd[x]=rand()*rand();
            return x;
        }
        if(val[x]>=v)
        {
            ls=insert(ls,v);
            size[x]++;fa[ls]=x;
            if(rnd[ls]>rnd[x])x=rotate(ls);
        }
        else
        {
            rs=insert(rs,v);
            size[x]++;fa[rs]=x;
            if(rnd[rs]>rnd[x])x=rotate(rs);
        }
        return x;
    }
    int query(int x,int v)
    {
        if(!x)return 0;
        if(val[x]<=v)
            return size[ls]+1+query(rs,v);
        else return query(ls,v);
    }
    void del(int x)
    {
        if(!x)return;
        que.push(x);
        del(ls);del(rs);
    }
}tr1;
struct tree_div
{
    int deep[N],fa[N][D],pre[N],rt[N],rt1[N][D];
    int size[N],size1[N][D],f[N],vis[N],root,sum;
    int sta[N][D],tp[N],sta1[D],top1;
    void init()
    {
        f[0]=1<<30;
        for(int i=1;i<=n;i++)
            vis[i]=1;
    }
    void ins(int x,int y)
    {
        for(int i=1;i<=tp[x];i++)
            if(sta[x][i]==y)return;
        sta[x][++tp[x]]=y;
    }
    void del(int x,int y,int v)
    {
        tr1.del(rt[x]),rt[x]=0;
        top1=0;
        for(int i=1,t;i<=tp[x];i++)
        {
            if((t=sta[x][i])>=v)
            {tr1.del(rt1[x][t]);rt1[x][t]=0;}
            else sta1[++top1]=t;
        }
        tp[x]=0;
        for(int i=1;i<=top1;i++)sta[x][++tp[x]]=sta1[i];

        for(int i=g.head[x];i;i=g.nex[i])
            if(g.to[i]!=y&&!vis[g.to[i]])
                del(g.to[i],x,v);
    }
    void dfs1(int x,int y,int t)
    {
        fa[x][deep[t]]=t;
        size[x]=1;
        for(int i=g.head[x];i;i=g.nex[i])
            if(g.to[i]!=y&&!vis[g.to[i]])
                dfs1(g.to[i],x,t),size[x]+=size[g.to[i]];
    }
    void dfs2(int x,int y)
    {
        f[x]=0;
        for(int i=g.head[x];i;i=g.nex[i])
            if(g.to[i]!=y&&!vis[g.to[i]])
                dfs2(g.to[i],x),f[x]=max(f[x],size[g.to[i]]);
        f[x]=max(f[x],sum-size[x]);
        root=f[x] < f[root] ? x:root;
    }
    void dfs3(int x,int y,int &rt,int dis)
    {
        rt=tr1.insert(rt,dis-r[x]);
        for(int i=g.head[x];i;i=g.nex[i])
            if(g.to[i]!=y&&!vis[g.to[i]])
                dfs3(g.to[i],x,rt,dis+g.val[i]);
    }
    void dfs4(int x,int y,int v)
    {
        if(deep[x]<=v)return;
        vis[x]=0;
        for(int i=g.head[x];i;i=g.nex[i])
            if(g.to[i]!=y)
                dfs4(g.to[i],x,v);
    }
    void rebuild(int x,int y)
    {
        dfs1(x,y,y);
        root=0;sum=size[x];
        dfs2(x,y);
        pre[root]=x;deep[root]=deep[y]+1;
        size[root]=sum;size1[x][deep[root]]=sum;

        dfs3(root,0,rt[root],0);
        vis[root]=1;
        for(int t=root,i=g.head[t];i;i=g.nex[i])
            if(g.to[i]!=y&&!vis[g.to[i]])
            {   
                ins(g.to[i],deep[t]);
                dfs3(g.to[i],t,rt1[g.to[i]][deep[t]],g.val[i]);
                rebuild(g.to[i],t);
            }
    }
    ll get(int x,int y,int c,int r)
    {
        top=0;ll ret=0;int org=x;
        g.add(x,y,c);g.add(y,x,c);
        deep[x]=deep[y]+1;pre[x]=x;
        size[x]=1;
        rt[x]=tr1.insert(rt[x],-r);

        for(int i=deep[y],d=c;i>=1;i--)
        {
            fa[org][i]=y;
            d=g.dis(org,y);     
            st[++top]=make_pair(x,y);
            size1[x][i]++;size[y]++;

            ret+=tr1.query(rt[y],r-d);
            ret-=tr1.query(rt1[x][i],r-d);

            rt[y]=tr1.insert(rt[y],d-r);
            rt1[x][i]=tr1.insert(rt1[x][i],d-r);
            ins(x,i);

            x=pre[y];y=fa[x][i-1];
        }
        for(int i=top,t,t1,y;i>=1;i--)
            if((double)size1[st[i].first][deep[st[i].second]]/size[y=st[i].second]>0.80)
            {
                t=fa[t1=pre[y]][deep[y]-1];
                dfs4(t1,t,deep[t]);vis[t]=1;
                del(t1,t,deep[y]);
                rebuild(t1,t);
                break;
            }
        return ret;
    }
}tr2;
int main()
{
    //freopen("ks.in","r",stdin);
    //freopen("ks.out","w",stdout);
    io.read();n=io.read();
    tr2.init();
    for(int i=1,y,c;i<=n;i++)   
    {
        y=io.read();c=io.read();r[i]=io.read();
        ans+=tr2.get(i,y=(y^ans%1000000000),c,r[i]);
        printf("%lld\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值