zoukankan      html  css  js  c++  java
  • bzoj 3435: [Wc2014]紫荆花之恋 替罪羊树维护点分治 && AC400

    3435: [Wc2014]紫荆花之恋

    Time Limit: 240 Sec  Memory Limit: 512 MB
    Submit: 159  Solved: 40
    [Submit][Status][Discuss]

    Description

    强 强和萌萌是一对好朋友。有一天他们在外面闲逛,突然看到前方有一棵紫荆树。这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来。 仔细看看的话,这个大树实际上是一个带权树。每个时刻它会长出一个新的叶子节点。每个节点上有一个可爱的小精灵,新长出的节点上也会同时出现一个新的小精 灵。小精灵是很萌但是也很脆弱的生物,每个小精灵 i 都有一个感受能力值Ri ,小精灵 i, j 成为朋友当且仅当在树上 i 和 j 的距离 dist(i,j) ≤ Ri + R! ,其中 dist(i, j)表示在这个树上从 i 到 j 的唯一路径上所有边的边权和。强强和萌萌很好奇每次新长出一个叶子节点之后,这个树上总共有几对朋友。 
    我们假定这个树一开始为空,节点按照加入的顺序从 1开始编号。由于强强非常好奇, 你必须在他每次出现新节点后马上给出总共的朋友对数,不能拖延哦。 

    Input


    共有 n + 2 行。
    第一行包含一个正整数,表示测试点编号。
    第二行包含一个正整数 n ,表示总共要加入的节点数。
    我们令加入节点前的总共朋友对数是 last_ans,在一开始时它的值为0。
    接下来 n 行中第 i 行有三个数 ai, bi, ri,表示节点  i  的父节点的编号为 ai xor (last_ans mod 10^9)   (其中xor 表示异或,mod  表示取余,数据保证这样操作后得到的结果介于 1到i  –  1之间),与父节点之间的边权为 ci,节点 i 上小精灵的感受能力值为r!。
    注意 a1 = c1 = 0,表示 1 号点是根节点,对于 i > 1,父节点的编号至少为1。

    Output

    包含 n 行,每行输出1 个整数, 表示加入第 i 个点之后,树上有几对朋友。

    Sample Input

    0
    5
    0 0 6
    1 2 4
    0 9 4
    0 5 5
    0 2 4

    Sample Output



    0
    1
    2
    4
    7

    HINT

    1<=Ci<=10000

    Ai<=2*10^9

    Ri<=10^9

    N<=100000

      本来以这道题的写法我是一定不会写题解的,但是这是我AC400,所以还是记录一下吧。

      树的点分治按照归属关系可以建成节点个数n深度log(n)的树,通过在树上维护平衡树来实现点分治,但是本题的加入节点会使整个分治树失衡,所以把他想成是替罪羊树,一旦失衡通过点分治重建整棵子树。

      不知道为什么就我一个人有常数问题。各种inline,register,读入优化,for循环合并,平衡树非递归。。。。。╮(╯▽╰)╭整整两天就砸这题里面了。

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    #define MAXN 450000
    #define MAXV MAXN
    #define MAXE MAXV*2
    #define MAXT MAXN*45
    #define INF 0x3f3f3f3f
    #define alpha 0.90
    typedef long long qword;
    const int maxbuf=100000;
    char buf[maxbuf*2];
    char *bufh(buf),*buft(buf+1);
    #define readbuf
    {
            if ((++bufh)==buft)
                    buft=(bufh=buf)+fread(buf,1,maxbuf,stdin);
    }
    #define nextInt(_r_)
    {
            register int _x_=0;
            do
            {
                    readbuf;
            }while (*bufh<'0' || *bufh>'9');
            do
            {
                    _x_=_x_*10+*bufh-'0';
                    readbuf;
            }while (*bufh<='9' && *bufh>='0');
            _r_=_x_;
    }
    /*
    inline int nextInt()
    {
            register char ch;
            register int x=0;
            while (ch=(char)getchar(),ch<'0' || ch>'9');
            while (x=x*10+ch-'0',ch=(char)getchar(),ch>='0' && ch<='9');
            return x;
    }
    */
    int pnt[MAXN],rr[MAXN],fdis[MAXN];
    int VV[MAXT],S[MAXT],L[MAXT],R[MAXT];
    int stack[MAXT];
    int tops;
    inline void init(int n)
    {
            tops=-1;
            int l=min(MAXT,n*50);
            for (register int i=1;i<l;i++)
                    stack[++tops]=MAXT-i;
            return ;
    }
    inline void update(int now)
    {
            S[now]=S[L[now]]+S[R[now]]+1;
    }
    inline void r_rotate(int &now)
    {
            register int t=L[now];
            L[now]=R[t];update(now);
            R[t]=now;update(t);
            now=t;
    }
    inline void l_rotate(int &now)
    {
            register int t=R[now];
            R[now]=L[t];update(now);
            L[t]=now;update(t);
            now=t;
    }
    inline void maintain(int &now)
    {
            if (S[L[L[now]]]>S[R[now]])
            {
                    r_rotate(now);
            //        maintain(L[now]);
            //        maintain(R[now]);
            //        maintain(now);
            }
            if (S[R[R[now]]]>S[L[now]])
            {
                    l_rotate(now);
            //        maintain(L[now]);
            //        maintain(R[now]);
            //        maintain(now);
            }
            if (S[L[R[now]]]>S[L[now]])
            {
                    r_rotate(R[now]);
                    l_rotate(now);
            //        maintain(L[now]);
            //        maintain(R[now]);
            //        maintain(now);
            }
            if (S[R[L[now]]]>S[R[now]])
            {
                    l_rotate(L[now]);
                    r_rotate(now);
            //        maintain(L[now]);
            //        maintain(R[now]);
            //        maintain(now);
            }
    }
    int *st[MAXN];
    void Insert(int &now,int v)
    {
            register int *nn;
            register int tops2=-1;
            if (!now)
            {
                    nn=&now;
            }else
            {
                    st[++tops2]=&now;
                    while (true)
                    {
                            if (v<=VV[*st[tops2]])
                            {
                                    if (!L[*st[tops2]])
                                    {
                                            nn=&L[*st[tops2]];
                                            break;
                                    }
                                    st[tops2+1]=&L[*st[tops2]];tops2++;
                            }
                            else
                            {
                                    if (!R[*st[tops2]])
                                    {
                                            nn=&R[*st[tops2]];
                                            break;
                                    }
                                    st[tops2+1]=&R[*st[tops2]];tops2++;
                            }
                    }
            }
            *nn=stack[tops--];
            if (L[*nn])stack[++tops]=L[*nn];
            if (R[*nn])stack[++tops]=R[*nn];
            VV[*nn]=v;
            S[*nn]=1;
            L[*nn]=R[*nn]=0;
            while (~tops2)
            {
                    update(*st[tops2]);
                    maintain(*st[tops2--]);
            }
    }
    int Get_rank2(register int now,int v)
    {
            register int ret=0;
            while (now)
            {
                    if (v<=VV[now])
                    {
                            ret+=S[R[now]]+1;
                            now=L[now];
                    }
                    else
                            now=R[now];
            }
            return ret;
    }
    void Scan(int &now)
    {
            if (!now)return ;
            Scan(L[now]);
            printf("%d ",VV[now]);
            Scan(R[now]);
    }
    struct Edge
    {
            int np,val;
            int lev;
            Edge *next,*neg;
    }E[MAXE],*V[MAXV];
    int tope=-1;
    inline void addedge(int x,int y,int z)
    {
            E[++tope].np=y;
            E[tope].next=V[x];
            E[tope].val=z;
            V[x]=&E[tope];
    }
    int rdis[MAXN],jump[18][MAXN];
    int depth[MAXN];
    inline int lca(int x,int y)
    {
            if (depth[x]<depth[y])swap(x,y);
            int dep=depth[x]-depth[y];
            for (register int i=0;i<18;i++)
                    if (dep & (1<<i))
                            x=jump[i][x];
            if (x==y)return x;
            for (register int i=17;i>=0;i--)
                    if (jump[i][x]!=jump[i][y])
                            x=jump[i][x],y=jump[i][y];
            return pnt[x];
    }
    inline int dis(int x,int y)
    {
            return rdis[x]+rdis[y]-2*rdis[lca(x,y)];
    }
    struct sct_edge
    {
            sct_edge *next;
            int np;
            int root;
    }sct[MAXN*5],*sctv[MAXN];
    int topse=-1;
    int scp[MAXN];
    sct_edge* scpe[MAXN];
    int scroot[MAXN];
    int sctlev[MAXN];
    int sctsiz[MAXN];
    inline void sct_addedge(int x,int y)
    {
            sct[++topse].np=y;
            sct[topse].next=sctv[x];
            sctv[x]=&sct[topse];
    }
    int q[MAXN];
    int pntt[MAXN];
    int siz[MAXN];
    int find_core(register int now)
    {
            register int head=-1,tail=0;
            register Edge *ne;
            q[0]=now;
            pntt[now]=now;
            while (head<tail)
            {
                    now=q[++head];
                    for (ne=V[now];ne;ne=ne->next)
                    {
                            if (ne->np==pntt[now] || ~ne->lev)continue;
                            q[++tail]=ne->np;
                            pntt[ne->np]=now;
                    }
            }
            int bstsiz=INF,core=-1;
            for (register int i=tail;i>=0;i--)
            {
                    now=q[i];
                    siz[now]=1;
                    int mxsiz=0;
                    for (ne=V[now];ne;ne=ne->next)
                    {
                            if (ne->np==pntt[now] || ~ne->lev)continue;
                            siz[now]+=siz[ne->np];
                            mxsiz=max(mxsiz,siz[ne->np]);
                    }
                    mxsiz=max(mxsiz,(tail+1)-siz[now]);
                    if (bstsiz>mxsiz)
                    {
                            bstsiz=mxsiz;
                            core=now;
                    }
            }
            return core;
    }
    int dstt[MAXN];
    void dfs2(register int now,int ds,int p,int &r1,int &r2,int lv)
    {
            register int head=-1,tail=0;
            register Edge *ne;
            q[0]=now;
            dstt[now]=ds;
            pntt[now]=p;
            while (head<tail)
            {
                    now=q[++head];
                    Insert(r1,rr[now]-dstt[now]);
                    Insert(r2,rr[now]-dstt[now]);
                    for (ne=V[now];ne;ne=ne->next)
                    {
                            if (ne->lev<lv || ne->np==pntt[now])continue;
                            pntt[ne->np]=now;
                            q[++tail]=ne->np;
                            dstt[ne->np]=dstt[now]+ne->val;
                    }
    
            }
    }
    int solve(int root,int lv)
    {
            register int core=find_core(root);
            register Edge *ne;
            sctlev[core]=lv;
            Insert(scroot[core],rr[core]-0);
            sctsiz[core]=siz[root];
            if (siz[root]==1)
                    return core;
            for (ne=V[core];ne;ne=ne->next)
            {
                    if (~ne->lev)continue;
                    ne->lev=ne->neg->lev=lv;
                    int t;
                    sct_addedge(core,t=solve(ne->np,lv+1));
                    scp[t]=core;
                    scpe[t]=sctv[core];
                    dfs2(ne->np,ne->val,core,scpe[t]->root,scroot[core],lv);
            }
            return core;
    }
    void sct_rebuild(register int now)
    {
            int head=-1,tail=0;
            int lv=sctlev[now];
            register sct_edge* ns;
            register Edge *ne;
            q[0]=now;
            while (head<tail)
            {
                    now=q[++head];
                    for (ns=sctv[now];ns;ns=ns->next)
                            q[++tail]=ns->np;
                    sctv[now]=0;
            }
            head=-1,tail=0;
            now=q[0];
            pntt[now]=now;
            while (head<tail)
            {
                    now=q[++head];
                    for (ne=V[now];ne;ne=ne->next)
                    {
                            if (ne->np==pntt[now] || ne->lev<lv)continue;
                            pntt[ne->np]=now;
                            ne->lev=ne->neg->lev=-1;
                            q[++tail]=ne->np;
                    }
            }
            int pt;
            sct_edge *pe;
            now=q[0];
            pe=scpe[now],pt=scp[now];
            for (int i=0;i<=tail;i++)
            {
                    now=q[i];
                    if (i && scpe[now]->root)
                            stack[++tops]=scpe[now]->root;
                    if (scroot[now])
                            stack[++tops]=scroot[now];
                    scroot[now]=0;
                    if (scpe[now])
                            scpe[now]=NULL;
            }
            now=solve(now,sctlev[q[0]]);
            //core->now
            if (pe)
                    pe->np=now;
            scpe[now]=pe;
            scp[now]=pt;
    }
    
    int main()
    {
            freopen("input.txt","r",stdin);
            freopen("output.txt","w",stdout);
            int x,n;
            /*
               int root=0;
               for (int i=1;i<100;i++)
               {
               Insert(root,rand()%1000);
               Scan(root);printf("
    ");
               }
               return 0;*/
            nextInt(x);
            qword ans=0;
            nextInt(n);
            init(n);
            int rebuild_pos;
            for (int i=1;i<=n;i++)
            {
                    nextInt(pnt[i]);
                    nextInt(fdis[i]);
                    nextInt(rr[i]);
                    //scanf("%d%d%d",&pnt[i],&fdis[i],&rr[i]);
                    //printf("%d
    ",i);
                    pnt[i]^=(int)(ans%1000000000);
                    if (i==1)
                    {
                            scp[i]=0;
                            scpe[i]=NULL;
                            sctlev[i]=1;
                            Insert(scroot[i],rr[i]-0);
                            sctsiz[i]=1;
                    }else
                    {
                            rdis[i]=rdis[pnt[i]]+fdis[i];
                            depth[i]=depth[pnt[i]]+1;
                            jump[0][i]=pnt[i];
                            for (register int j=1;j<18;j++)
                                    jump[j][i]=jump[j-1][jump[j-1][i]];
                            scp[i]=pnt[i];
                            sct_addedge(pnt[i],i);
                            sctlev[i]=sctlev[scp[i]]+1;
                            addedge(pnt[i],i,fdis[i]);
                            addedge(i,pnt[i],fdis[i]);
                            V[i]->neg=V[pnt[i]];V[pnt[i]]->neg=V[i];
                            V[i]->lev=V[pnt[i]]->lev=sctlev[pnt[i]];
                            scpe[i]=sctv[pnt[i]];
                            register sct_edge* ns;
                            sctsiz[i]++;
                            int d;
                            rebuild_pos=-1;
                            Insert(scroot[i],rr[i]-0);
                            for (ns=scpe[i],x=scp[i],d=fdis[i];ns;ns=scpe[x],x=scp[x],d=dis(i,x))
                            {
                                    //    printf("[+]");Scan(scroot[x]);printf("
    ");
                                    //    printf("[-]");Scan(ns->root);printf("
    ");
                                    //    printf("[F]%d
    ",d-rr[i]);
                                    ans+=Get_rank2(scroot[x],d-rr[i])-Get_rank2(ns->root,d-rr[i]);
                                    Insert(scroot[x],rr[i]-d);
                                    Insert(ns->root,rr[i]-d);
                                    sct_edge *ns2;
                                    sctsiz[x]++;
                                    for (ns2=sctv[x];ns2;ns2=ns2->next)
                                    {
                                            if (sctsiz[ns2->np]>sctsiz[x]*alpha)
                                                    rebuild_pos=x;
                                    }
                            }
                            //sct_rebuild(rand()%i+1);
                            if (~rebuild_pos)
                                    sct_rebuild(rebuild_pos);
                    }
                    printf("%lld
    ",ans);
            }
    }

    `

    by mhy12345(http://www.cnblogs.com/mhy12345/) 未经允许请勿转载

    本博客已停用,新博客地址:http://mhy12345.xyz

  • 相关阅读:
    oracle 强杀进程
    oracle查询使用频率和磁盘消耗需要缓存大小
    Oracle定时器执行多线程
    Python
    Python- XML模块
    Python-标准库之OS模块
    Python
    Python-时间复杂度
    Python-冒泡排序
    Python-正则表达式
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4328648.html
Copyright © 2011-2022 走看看