zoukankan      html  css  js  c++  java
  • BZOJ3435 & 洛谷3920 & UOJ55:[WC2014]紫荆花之恋

    https://www.lydsy.com/JudgeOnline/problem.php?id=3435

    https://www.luogu.org/problemnew/show/P3920

    http://uoj.ac/problem/55

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

    对着题解的指针魔改了一个在洛谷开O2可过,其他网站可过的数组版。

    题解请见:https://www.luogu.org/blog/user15268/solution-p3920

    其实理解起来还是很好理解的,关键就在于你的卡常姿势以及代码能力的问题了。

    (然而考场谁写谁跪的谁敢写这东西……)

    简单叙述题解:

    树不会动的时候显然点分治,把条件拆开即可用平衡树维护做(比较基础的点分治,具体做法看参考)。

    树会动思考点分治并非一定要重心,只有当差的太离谱时为了效率将点重新变为重心就行。

    这就是替罪羊树的思想了:暴力维护,失衡时暴力重建。我们把这样的点所构成的结构叫做点分树。

    那最开始的点分树就随便搞,失衡了再静态维护一下即可。

    总代码压行后198行……应该不影响阅读,因为linux的问题缩进被吃了一些请见谅。

    #include<cmath>
    #include<stack>
    #include<vector>
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef double dl;
    const int N=1e5+5;
    const int mod=1e9;
    const dl alpha=0.812345;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    inline void put(ll x){
        if(x>9)put(x/10);
        putchar(x%10+48);
    }
    struct node{
        int to,nxt,w;
    }e[N*2];
    int cnt,head[N],r[N],fa[N],size[N],son[N],dis[N],n,q[N];
    vector<int>anc[N],id[N],sons[N];
    bool vis[N];
    ll ans;
    int t[40*N][2],s[40*N],p[40*N],w[40*N];
    int sz,rt[2*N];
    stack<int>bin;
    inline void add(int u,int v,int w){
        e[++cnt].to=v;e[cnt].w=w;e[cnt].nxt=head[u];head[u]=cnt;
    }
    inline int rand(){
        static int seed=233;
        return seed=(ll)seed*482711%998244353;
    }
    inline int f(int x){return x+n;}
    inline int getnod(){
        if(!bin.empty()){
        int u=bin.top();bin.pop();
        return u;
        }
        return ++sz;
    }
    inline void upt(int k){
        s[k]=s[t[k][0]]+s[t[k][1]]+1;
    }
    inline void zig(int &k){
        int y=t[k][0];t[k][0]=t[y][1];t[y][1]=k;
        s[y]=s[k];upt(k);
        k=y;
    }
    inline void zag(int &k){
        int y=t[k][1];t[k][1]=t[y][0];t[y][0]=k;
        s[y]=s[k];upt(k);
        k=y;
    }
    inline void del(int &k){
        if(!k)return;
        bin.push(k);
        if(t[k][0])del(t[k][0]);
        if(t[k][1])del(t[k][1]);
        k=0;
    }
    inline void insert(int &k,int val){
        if(!k){
        k=getnod();w[k]=val;p[k]=rand();
        s[k]=1;t[k][0]=t[k][1]=0;
        return;
        }
        else ++s[k];
        if(val<=w[k]){
        insert(t[k][0],val);
        if(p[t[k][0]]<p[k])zig(k);
        }else{
        insert(t[k][1],val);
        if(p[t[k][1]]<p[k])zag(k);
        }
    }
    inline int find(int x,int val){
        int res=0;
        while(x){
        if(val<w[x])x=t[x][0];
        else res+=s[t[x][0]]+1,x=t[x][1];
        }
        return res;
    }
    int calcg(int st){
        int R=0,g,maxn=n;
        q[++R]=st;fa[st]=0;
        for(int L=1;L<=R;++L){
        int u=q[L];
        size[u]=1;son[u]=0;
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(!vis[v]||v==fa[u])continue;
            fa[v]=u;q[++R]=v;
        }
        }
        for(int L=R;L>=1;--L){
        int u=q[L],v=fa[u];
        if(R-size[u]>son[u])son[u]=R-size[u];
        if(son[u]<maxn)g=u,maxn=son[u];
        if(!v)break;
        size[v]+=size[u];
        if(size[u]>son[v])son[v]=size[u];
        }
        return g;
    }
    inline void dac(int st,int par){
        int R=0,g=calcg(st);vis[g]=0;
        q[++R]=g;fa[g]=0;dis[g]=0;
        for(int L=1;L<=R;++L){
        int u=q[L];
        for(int j=head[u];j;j=e[j].nxt){
            int v=e[j].to;
            if(!vis[v]||v==fa[u])continue;
            fa[v]=u;dis[v]=dis[u]+e[j].w;
            q[++R]=v;
        }
        }
        for(int L=1;L<=R;++L){
        int u=q[L];
        id[u].push_back(g);
        anc[u].push_back(dis[u]);
        sons[g].push_back(u);
        insert(rt[g],dis[u]-r[u]);
        if(par)insert(rt[f(g)],anc[u][anc[u].size()-2]-r[u]);
        }
        for(int i=head[g];i;i=e[i].nxt){
        int v=e[i].to;
        if(vis[v])dac(v,g);
        }
    }
    vector<int>tmp;
    inline void rebuild(int u,int par){
        tmp=sons[u];
        int len=anc[par].size();
        for(int i=0;i<tmp.size();++i){
        int v=tmp[i];vis[v]=1;
        sons[v].clear();
        anc[v].resize(len);
        id[v].resize(len);
        del(rt[v]);del(rt[f(v)]);
        }
        dac(u,par);
    }
    inline void check(int u){
        for(int i=0;i<id[u].size();++i){
        insert(rt[id[u][i]],anc[u][i]-r[u]);
        if(i)insert(rt[f(id[u][i])],anc[u][i-1]-r[u]);
        }
        for(int i=0;i<id[u].size()-1;++i){
        int sz_f=s[rt[id[u][i]]];
        int sz_s=s[rt[id[u][i+1]]];
        if(sz_f<=30)return;
        if(sz_s>alpha*sz_f){
            rebuild(id[u][i],(!i)?0:id[u][i-1]);
            return;
        }
        }
    }
    inline int solve(int u,int v,int w){
        int res=0;
        anc[u]=anc[v];id[u]=id[v];
        anc[u].push_back(-w);id[u].push_back(u);
        for(int i=0;i<anc[u].size();++i){
        anc[u][i]+=w;
        sons[id[u][i]].push_back(u);
        res+=find(rt[id[u][i]],r[u]-anc[u][i]);
        if(i)res-=find(rt[f(id[u][i])],r[u]-anc[u][i-1]);
        }
        return res;
    }
    int main(){
        read();n=read();
        for(int i=1;i<=n;++i){
        int u=read()^(ans%mod),w=read();r[i]=read();
        if(i==1){
            anc[i].push_back(0);
            id[i].push_back(i);
            sons[i].push_back(i);
            insert(rt[i],-r[i]);
            puts("0");
            continue;
        }
        add(u,i,w);add(i,u,w);
        ans+=solve(i,u,w);
        check(i);
        put(ans);putchar('
    ');
        }
        return 0;
    }
  • 相关阅读:
    二分匹配
    第k短路
    2015_10
    The 15th Zhejiang University Programming Contest
    2015_8
    hdu 1565
    istringstream 用法
    floyd 闭包传递 判断两个点是否属于同一个 强连通分量
    Sicily 1866.Gene Reprogram 一种经典的hash方法
    zoj 3130 最小费用最大流 (求 s到e 的两条总花费最少的 完全没有交点的 路径)
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9047751.html
Copyright © 2011-2022 走看看