bzoj 3052: [wc2013]糖果公园树上带修改莫队

Posted lokiii

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3052: [wc2013]糖果公园树上带修改莫队相关的知识,希望对你有一定的参考价值。

参考:http://blog.csdn.net/lych_cys/article/details/50845832
把树变成dfs括号序的形式,注意这个是不包含lca的(除非lca是两点中的一个)
然后把询问按照所属块一序,r二序,t三序排序(注意a和b数组的同名变量意思不一样),对于每个询问处理修改,时间正流或者逆流,修改答案时用vis数组记录这个位置是否在答案中被统计过来决定加减。对于修改序列的操作,如果他没有被统计在答案里就直接修改,否则修改答案。对lca特殊处理

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=200005;
int n,m,q,u[N],v[N],w[N],h[N],cnt,c[N],la[N],kuai,f[N],g[N],dfn,bl[N],cnta,cntb;
int de[N],fa[N],fr[N],si[N],hs[N],rl[N];
long long ans[N],sum;
bool vis[N];
struct qw
{
    int ne,to;
}e[N<<1];
struct qwe
{
    int l,r,t,rl;
}a[N],b[N];//对于b,l是位置,r是修改为的颜色,t是上一个颜色
bool cmp(qwe x,qwe y)
{
    return bl[x.l]<bl[y.l]||bl[x.l]==bl[y.l]&&bl[x.r]<bl[y.r]||bl[x.l]==bl[y.l]&&bl[x.r]==bl[y.r]&&x.t<y.t;
}
int read()
{
    int r=0;
    char p=getchar();
    while(p>‘9‘||p<‘0‘)
        p=getchar();
    while(p>=‘0‘&&p<=‘9‘)
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r;
}
void add(int u,int v)
{
    cnt++;
    e[cnt].ne=h[u];
    e[cnt].to=v;
    h[u]=cnt;
}
void dfs1(int u,int fat)
{
    fa[u]=fat;
    de[u]=de[fat]+1;
    si[u]=1;
    f[u]=++dfn;
    rl[dfn]=u;
    for(int i=h[u];i;i=e[i].ne)
        if(e[i].to!=fat)
        {
            dfs1(e[i].to,u);
            si[u]+=si[e[i].to];
            if(si[e[i].to]>si[hs[u]])
                hs[u]=e[i].to;
        }
    g[u]=++dfn;
    rl[dfn]=u;
}
void dfs2(int u,int top)
{
    fr[u]=top;
    if(!hs[u])
        return;
    dfs2(hs[u],top);
    for(int i=h[u];i;i=e[i].ne)
        if(e[i].to!=fa[u]&&e[i].to!=hs[u])
            dfs2(e[i].to,e[i].to);
}
int lca(int u,int v)
{
    for(;fr[u]!=fr[v];de[fr[u]]>de[fr[v]]?u=fa[fr[u]]:v=fa[fr[v]]);
    return de[u]>de[v]?v:u;
}
void add(int x)
{
    if(vis[x])
        sum-=(long long)v[c[x]]*w[u[c[x]]--];
    else
        sum+=(long long)v[c[x]]*w[++u[c[x]]];
    vis[x]^=1;
}
void change(int x,int y)
{
    if(vis[x])
    {
        add(x);
        c[x]=y;
        add(x);
    }
    else
        c[x]=y;
}
int main()
{
    n=read(),m=read(),q=read();
    for(int i=1;i<=m;i++)
        v[i]=read();
    for(int i=1;i<=n;i++)
        w[i]=read();
    for(int i=1;i<n;i++)
    {
        int x=read(),y=read();
        add(x,y);add(y,x);
    }
    for(int i=1;i<=n;i++)
        c[i]=la[i]=read();
    kuai=(int)pow(n,2.0/3);
    dfs1(1,0);
    dfs2(1,1);
    for(int i=1;i<=dfn;i++)
        bl[i]=(i-1)/kuai;
    while(q--)
    {
        int t=read(),l=read(),r=read();
        if(t==0)
        {
            b[++cntb].l=l;
            b[cntb].t=la[l];
            la[l]=b[cntb].r=r;
        }
        else
        {
            if(f[l]>f[r])
                swap(l,r);
            a[++cnta].r=f[r];
            a[cnta].rl=cnta;
            a[cnta].t=cntb;//cout<<lca(l,r)<<endl;
            a[cnta].l=(lca(l,r)==l)?f[l]:g[l];
        }
    }
    sort(a+1,a+cnta,cmp);
    int l=1,r=0,t=1;
    for(int i=1;i<=cnta;i++)
    {
        for(;t<=a[i].t;t++)
            change(b[t].l,b[t].r);
        for(;t>a[i].t;t--)
            change(b[t].l,b[t].t);
        while(l>a[i].l)
            add(rl[--l]);
        while(l<a[i].l)
            add(rl[l++]);
        while(r>a[i].r)
            add(rl[r--]);
        while(r<a[i].r)
            add(rl[++r]);
        int x=rl[l],y=rl[r],tmp=lca(x,y);//cout<<x<<" "<<y<<" "<<tmp<<endl;
        if(x!=tmp&&y!=tmp)
        {
            add(tmp);
            ans[a[i].rl]=sum;
            add(tmp);
        }
        else
            ans[a[i].rl]=sum;
    }
    for(int i=1;i<=cnta;i++)
        printf("%lld\n",ans[i]);
    return 0;
}
/*
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
*/

以上是关于bzoj 3052: [wc2013]糖果公园树上带修改莫队的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3052 [wc2013] 糖果公园 树上莫队

bzoj 3052: [wc2013]糖果公园树上带修改莫队

BZOJ3052 WC2013 糖果公园

bzoj3052: [wc2013]糖果公园

[BZOJ3052][UOJ#58][WC2013]糖果公园

[bzoj 3052][wc2013]糖果公园