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("\n");
           }
           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\n",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("\n");
                                //    printf("[-]");Scan(ns->root);printf("\n");
                                //    printf("[F]%d\n",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\n",ans);
        }
}

`

时间: 2024-10-25 02:33:24

bzoj 3435: [Wc2014]紫荆花之恋 替罪羊树维护点分治 && AC400的相关文章

BZOJ 3435 Wc2014 紫荆花之恋 动态树分治+替罪羊树+Treap

题目大意:给定一棵树,每次添加一个节点并询问当前有多少点对满足dis(i,j)<=ri+rj 强制在线 吾辈有生之年终于把这道题切了...QAQ 什么?你想做这题? 1095切了么?没?去把1095切掉再说! 3065切了么?没?去把3065切掉再说! 什么?都切了?那还不会做这题?? -- 算了还是说说做法吧... 我们抛开那些乱七八糟的,考虑朴素做法 首先式子的形式是dis(i,j)<=ri+rj,令p=lca(i,j),把式子变形可以得到dis(j,p)-rj<=ri-dis(i,

BZOJ 3435: [Wc2014]紫荆花之恋

二次联通门 : BZOJ 3435: [Wc2014]紫荆花之恋 二次联通门 : luogu P3920 [WC2014]紫荆花之恋 /* luogu P3920 [WC2014]紫荆花之恋 怀疑人生 */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <ctime> #include <algorithm> #de

【BZOJ3435】[Wc2014]紫荆花之恋 替罪点分树+SBT

[BZOJ3435][Wc2014]紫荆花之恋 Description 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每个时刻它会长出一个新的叶子节点.每个节点上有一个可爱的小精灵,新长出的节点上也会同时出现一个新的小精灵.小精灵是很萌但是也很脆弱的生物,每个小精灵 i 都有一个感受能力值Ri ,小精灵 i, j 成为朋友当且仅当在树上 i 和 j 的距离

Wc2014 紫荆花之恋

哈哈哈哈哈哈哈哈哈哈哈哈我终于过了!!!!!!!!!!!!!!! 从昨天上午就开始写了,下午回家之后调了一会儿没什么感觉,就删了重打了一遍,然后调了一晚上+今天半个上午......我*******终于过了...... 我是萌萌的传送门 我是另一个萌萌的传送门 一道极其恶心的动态树分治...... 首先点分治,限制条件就变成了di+dj<=ri+rj,移项得rj-dj>=di-ri,对重心和子树开平衡树维护di-ri即可. 查询的时候先跳点分治树更新答案,然后逐层把di-ri插入平衡树,上跳的过

【bzoj3435】[Wc2014]紫荆花之恋 替罪点分树套SBT

题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每个时刻它会长出一个新的叶子节点.每个节点上有一个可爱的小精灵,新长出的节点上也会同时出现一个新的小精灵.小精灵是很萌但是也很脆弱的生物,每个小精灵 i 都有一个感受能力值Ri ,小精灵 i, j 成为朋友当且仅当在树上 i 和 j 的距离 dist(i,j) ≤ Ri + R! ,其中 dist(i

UOJ#55 [WC2014]紫荆花之恋

题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这个大树实际上是一个带权树.每个时刻它会长出一个新的叶子节点,每个节点上有一个可爱的小精灵,新长出的节点上也会同时出现一个新的小精灵.小精灵是很萌但是也很脆弱的生物,每个小精灵 \(i\) 都有一个感受能力值 \(r_i\),小精灵 \(i, j\) 成为朋友当且仅当在树上 \(i\) 和 \(j\) 的距离 \(\text{

[BZOJ 3995] [SDOI2015] 道路修建 【线段树维护连通性】

题目链接:BZOJ - 3995 题目分析 这道题..是我悲伤的回忆.. 线段树维护连通性,与 BZOJ-1018 类似,然而我省选之前并没有做过  1018,即使它在 ProblemSet 的第一页. 更悲伤的是,这道题有 40 分的暴力分,写个 Kruskal 就可以得到,然而我写了个更快的 DP . 这本来没有什么问题,然而我的 DP 转移少些了一种情况,于是...爆零.没错,省选前20名可能就我没有得到这 40 分? 不想再多说什么了...希望以后不要再这样 SB 了,如果以后还有机会的

P3920 [WC2014]紫荆花之恋 [点分树,替罪羊树]

点分树搞出来,然后搞个快点的平衡树. 点分树膨胀的时候就搞重构,没了...说的这么轻巧倒是写了3h 23333 // powered by c++11 // by Isaunoya #include <bits/stdc++.h> #define rep(i, x, y) for (register int i = (x); i <= (y); ++i) #define Rep(i, x, y) for (register int i = (x); i >= (y); --i) #

[题解] bzoj 3600 没有人的算数 (替罪羊树+线段树)

- 传送门 - http://www.lydsy.com/JudgeOnline/problem.php?id=3600 - 思路 - 区间操作是线段树无疑,难点在于如何考虑这些数对的大小关系. 我们考虑一下平衡树,如果在平衡树中每个节点放一个数对,我们规定中序遍历前面的数对大于后面的,那么对于任意一个新数对(x,y)插入时只需知道x,y与每个节点的数对的关系,就可以在log的时间内放入. 对于x,y与某节点数对的关系,首先要知道x,y一定在平衡树中存在(否则怎么被用来构成新数对?),因此可以l