zoukankan      html  css  js  c++  java
  • BZOJ3052 & UOJ58:[WC2013]糖果公园——题解

    http://uoj.ac/problem/58

    http://www.lydsy.com/JudgeOnline/problem.php?id=3052

    输入格式

    输出格式

    input

    4 3 5
    1 9 2
    7 6 5 1
    2 3
    3 1
    3 4
    1 2 3 2
    1 1 2
    1 4 2
    0 2 1
    1 1 2
    1 4 2
    

    output

    84
    131
    27
    84

    ——————————————————————————————————————

    这题对于一个刚学莫队的人来说……挺萌的。

    首先先对树分块,具体请看我的前一篇博客王室联邦我们就可以知道,假设我们要分块,我们设预期分块大小为s,则所有块的大小可为[s,3s]。

    按照这种分块方法分块即可,注意为了我们算法的速度,分块大小s=n的2/3次方,证明可看小兔大佬的博客中单点修改莫队

    (dfs同时预处理LCA所需要的几个数据,以后会用)

    在那之后按照莫队的思路为询问排序,然后开始我们正式的算法。

    (排序时0号点的l和r都设成1(看到下面的操作之后就会知道这样做干什么了))

    这里说一下个别几个数组的含义。

    1.sta[i]:i是否在当前路径上,是为1.

    2.last[i]:第i个操作为修改时,修改前的颜色。

    3.cc[i]:最终i点的颜色。

    4.col[i]:当前操作时i点的颜色。

    再说一个函数rev(i)表示将i这个点在我们的路径上被添加/删除。

    剩下的应该都能看得懂,我就不说什么了。

    首先按照排序后顺序扫询问,我们得到了我们当前的询问和前一个询问。

    那么首先我们需要将前一个询问的id和后一个询问的id中间的修改操作修改了。

    然后就是最神奇的操作了,solve操作的证明详见vfk的博客

    (当然你也可以通过画图肉眼观察法证明,以下简述solve内部操作)

    我们把当前的左询问节点l和之前的左询问节点l0之间的最短路取反。(当然同时对右节点也是一样)

    然后取反左右询问节点的LCA,再更新cur,在取反LCA,这样我们就得到了这个询问的答案了。

    #include<cstdio>
    #include<stack>
    #include<cctype>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=100001;
    const int INF=2147483647;
    inline ll read(){
        ll 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;
    }
    struct node{
        int to;
        int nxt;
    }edge[N*2];
    struct qu{
        int id,l,r,bl,br;
    }qry[N];
    int n,m,Q,q,s,cnt,head[N];
    int top,idx,stk[N],blk[N];
    int anc[N][20],dep[N];
    int v[N],cc[N],col[N],sum[N];
    int a[N],b[N],op[N],last[N];
    ll cur,ans[N],w[N];
    bool sta[N];
    inline void add(int u,int v){
        cnt++;
        edge[cnt].to=v;
        edge[cnt].nxt=head[u];
        head[u]=cnt;
        return;
    }
    bool cmp(qu d,qu e){
        if(d.bl!=e.bl)return d.bl<e.bl;
        if(d.br!=e.br)return d.br<e.br;
        return d.id<e.id;
    }
    void dfs(int u){
        int st=top;
        dep[u]=dep[anc[u][0]]+1;
        for(int i=head[u];i;i=edge[i].nxt){
            int v=edge[i].to;
            if(v==anc[u][0])continue;
        anc[v][0]=u;
        dfs(v);
        if(top-st>=s){
            idx++;
            while(top>st)blk[stk[top--]]=idx;
        }
        }
        stk[++top]=u;
        return;
    }
    int LCA(int i,int j){
        if(dep[i]<dep[j])swap(i,j);
        for(int k=17;k>=0;k--){
            if(dep[anc[i][k]]>=dep[j])i=anc[i][k];
        }
        if(i==j)return i;
        for(int k=17;k>=0;k--){
            if(anc[i][k]!=anc[j][k])i=anc[i][k],j=anc[j][k];
        }
        return anc[i][0];
    }
    void init(){
        n=read();m=read();Q=read();s=pow(n,2.0/3.0);
        for(int i=1;i<=m;i++)v[i]=read();
        for(int i=1;i<=n;i++)w[i]=read()+w[i-1];
        for(int i=1;i<n;i++){
            int u=read(),v=read();
            add(u,v);add(v,u);
        }
        for(int i=1;i<=n;i++)cc[i]=col[i]=read();
        dfs(1);
        while(top)blk[stk[top--]]=idx;
        for(int j=1;j<=17;j++){
            for(int i=1;i<=n;i++){
                anc[i][j]=anc[anc[i][j-1]][j-1];
            }
        }
        return;
    }
    inline void rev(int x){
        cur-=w[sum[col[x]]]*v[col[x]];
        sta[x]?sum[col[x]]--:sum[col[x]]++;
        sta[x]=!sta[x];
        cur+=w[sum[col[x]]]*v[col[x]];
        return;
    }
    inline void solve(int x,int y){
        int l=LCA(x,y);
        while(x!=l)rev(x),x=anc[x][0];
        while(y!=l)rev(y),y=anc[y][0];
        return;
    }
    inline void modify(int x,int y){
        if(!sta[x]){
        col[x]=y;
        return;
        }
        rev(x);
        col[x]=y;
        rev(x);
        return;
    }
    inline void upt(int tarT,int curT){
        while(curT<tarT){
        curT++;
        if(!op[curT])modify(a[curT],b[curT]);
        }
        while(curT>tarT){
        if(!op[curT])modify(a[curT],last[curT]);
        curT--;
        }
        return;
    }
    int main(){
        init();
        for(int i=1;i<=Q;i++){
        op[i]=read(),a[i]=read(),b[i]=read();
        if(op[i]){
            qry[++q].id=i;
            if(blk[a[i]]>blk[b[i]])swap(a[i],b[i]);
            qry[q].l=a[i];qry[q].r=b[i];
            qry[q].bl=blk[a[i]];qry[q].br=blk[b[i]];
        }else last[i]=cc[a[i]],cc[a[i]]=b[i];
        }
        sort(qry+1,qry+q+1,cmp);
        qry[0].l=qry[0].r=1;
        for(int i=1;i<=q;i++){
        upt(qry[i].id,qry[i-1].id);
        solve(qry[i].l,qry[i-1].l);solve(qry[i].r,qry[i-1].r);
        int l=LCA(qry[i].l,qry[i].r);
        rev(l);
        ans[qry[i].id]=cur;
        rev(l);
        }
        for(int i=1;i<=Q;i++){
        if(op[i])printf("%lld
    ",ans[i]);
        }
        return 0;
    }
  • 相关阅读:
    神奇的JavaScript之正则
    神奇的JavaScript之Function
    实现img包含在容量居中显示
    《JavaScript patterns》读书笔记
    多线程下的单例模式你真的了解吗?
    分享一个很不错的编程学习网站:https://www.lidihuo.com
    史上最全使用Nexus搭建Maven服务器详细配置
    SqlServer内存释放
    JS对url编码
    未能加载文件或程序集 XX 或它的某一个依赖项
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8185484.html
Copyright © 2011-2022 走看看