WC2013 糖果公园

Posted 日拱一卒 功不唐捐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WC2013 糖果公园相关的知识,希望对你有一定的参考价值。

COGS 1817. [WC2013]糖果公园

http://www.cogs.pro/cogs/problem/problem.php?pid=1817

★★★☆   输入文件:park.in   输出文件:park.out   简单对比
时间限制:8 s   内存限制:512 MB

【题目描述】

 

    Candyland 有一座糖果公园,公园里不仅有美丽的风景、好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园玩。

    糖果公园的结构十分奇特,它由 n 个游览点构成,每个游览点都有一个糖果发放处,我们可以依次将游览点编号为 1 至 n。有 n−1 条双向道路连接着这些游览点,并且整个糖果公园都是连通的,即从任何一个游览点出发都可以通过这些道路到达公园里的所有其它游览点。

    糖果公园所发放的糖果种类非常丰富,总共 m 种,它们的编号依次为 1 至 m。每一个糖果发放处都只发放某种特定的糖果,我们用 ci 来表示 i 号游览点的糖果。

    来到公园里游玩的游客都不喜欢走回头路,他们总是从某个特定的游览点出发前往另一个特定的游览点,并游览途中的景点,这条路线一定是唯一的。他们经过每个游览点,都可以品尝到一颗对应种类的糖果。

    大家对不同类型的糖果的喜爱程度都不尽相同。根据游客们的反馈打分,我们得到了糖果的美味指数,第 i 种糖果的美味指数为 vi。另外,如果一位游客反复地品尝同一种类的糖果,他肯定会觉得有一些腻。根据量化统计,我们得到了游客第 i 次品尝某类糖果的新奇指数 wi,如果一位游客第 i 次品尝第 j 种糖果,那么他的愉悦指数 H 将会增加对应的美味指数与新奇指数的乘积,即 vjwi。这位游客游览公园的愉悦指数最终将是这些乘积的和。

    当然,公园中每个糖果发放点所发放的糖果种类不一定是一成不变的。有时,一些糖果点所发放的糖果种类可能会更改(也只会是 m 种中的一种),这样的目的是能够让游客们总是感受到惊喜。

    糖果公园的工作人员小 A 接到了一个任务,那就是根据公园最近的数据统计出每位游客游玩公园的愉悦指数。但数学不好的小 A 一看到密密麻麻的数字就觉得头晕,作为小 A 最好的朋友,你决定帮他一把。

 

【输入格式

 

    第一行包含三个正整数 n,m,q,分别表示游览点个数、糖果种类数和操作次数。

    第二行包含 m 个正整数 v1,v2,…,vm。

    第三行包含 n 个正整数 w1,w2,…,wn。

    第四行到第 n+2 行,每行包含两个正整数 ai,bi,表示这两个游览点之间有路径可以直接到达。

    第 n+3 行包含 n 个正整数 c1,c2,…,cn。

    接下来 q 行,每行包含三个整数 t,x,y,表示一次操作:

    若 t 为 0,则 1≤x≤n,1≤y≤m,表示编号为 x 的游览点发放的糖果类型改为 y;

    若 t 为 1,则 1≤x,y≤n,表示对出发点为 x,终止点为 y 的路线询问愉悦指数。

 

【输出格式

 

    按照输入的先后顺序,对于每个 t 为 1 的操作输出一行,用一个正整数表示答案。

 

【样例输入】

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

【样例输出】

84
131
27
84

【数据范围】

    对于所有的数据,1≤vi,wi≤10^6,1≤ai,bi≤n,1≤ci≤m,w1,w2,…,wn 是非递增序列,即对任意 1<i≤n,满足 wi≤wi−1。

 

技术分享

树上带修改莫队

#include<cmath>
#include<cstdio>
#include<algorithm>
#define N 100001
using namespace std;
int n,m,q,siz;
int tasty[N],curious[N],type[N];
int front[N],to[N<<1],nxt[N<<1],tot;
int now,cnt,block[N],sum[N];
int son[N],deep[N],dfn[N],bl[N],fa[N];
long long tmp,ans[N];
bool v[N];
struct QUERY
{
    int l,r,id,tim;
    bool operator < (QUERY p)const
    {
        if(block[l]!=block[p.l]) return block[l]<block[p.l];
        if(block[r]!=block[p.r]) return block[r]<block[p.r];
        return tim<p.tim;
    }
}e[N];
struct CHANGE
{
    int pos,be,af;
}g[N];
void read(int &x)
{
    x=0; char c=getchar();
    while(c<0||c>9) c=getchar();
    while(c>=0&&c<=9) { x=x*10+c-0; c=getchar(); }
}
void out(long long x)
{
    if(x/10) out(x/10);
    putchar(x%10+0);
}
void add(int u,int v)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
}
void init()
{
    read(n); read(m); read(q);
    siz=sqrt(n);
    for(int i=1;i<=m;i++) read(tasty[i]);
    for(int i=1;i<=n;i++) read(curious[i]);
    int u,v;
    for(int i=1;i<n;i++)
    {
        read(u); read(v);
        add(u,v);
    }
    for(int i=1;i<=n;i++) read(type[i]);
    int w;
    tot=0;
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d%d",&w,&u,&v);
        if(!w)
        {
            g[++now].pos=u; g[now].af=v;
        }
        else
        {
            e[++cnt].l=u; e[cnt].r=v; e[cnt].id=cnt; e[cnt].tim=now;
        }
    }
}
void dfs1(int x)
{
    son[x]++;
    for(int i=front[x];i;i=nxt[i])
    {
        if(to[i]==fa[x]) continue;
        deep[to[i]]=deep[x]+1;
        fa[to[i]]=x;
        dfs1(to[i]);
        son[x]+=son[to[i]];
    }
}
void dfs2(int x,int top)
{
    dfn[x]=++tot;
    bl[x]=top;
    block[x]=(tot-1)/siz+1;
    int y=0;
    for(int i=front[x];i;i=nxt[i])
    {
        if(to[i]==fa[x]) continue;
        if(son[to[i]]>son[y]) y=to[i];
    }
    if(!y) return;
    dfs2(y,top);
    for(int i=front[x];i;i=nxt[i])
    {
        if(to[i]==fa[x]||to[i]==y) continue;
        dfs2(to[i],to[i]);
    }
}
int get_lca(int u,int v)
{
    while(bl[u]!=bl[v])
    {
        if(deep[bl[u]]<deep[bl[v]]) swap(u,v);
        u=fa[bl[u]];
    }
    if(deep[u]>deep[v]) swap(u,v);
    return u;
}
void point(int x)
{
    if(v[x])  
    {
        long long o=curious[sum[type[x]]--];
        tmp-=1ll*tasty[type[x]]*o;
    }
    else 
    {
        long long o=curious[++sum[type[x]]];
        tmp+=1ll*tasty[type[x]]*o;
    }
    v[x]^=1;
}
void path(int u,int v)
{
    while(u!=v)
    {
        if(deep[u]<deep[v]) point(v),v=fa[v];
        else point(u),u=fa[u];
    }
}
void solve()
{
    int L=1,R=1,lca; now=0;
    for(int i=1;i<=cnt;i++)
    {
        if(i==4)
        {
            int gra=5;
        }
        while(now<e[i].tim)
        {
            now++;
            g[now].be=type[g[now].pos];
            if(v[g[now].pos])
            {
                point(g[now].pos);
                type[g[now].pos]=g[now].af;
                point(g[now].pos);
            }
            else  type[g[now].pos]=g[now].af;
        }
        while(now>e[i].tim)
        {
            if(v[g[now].pos])
            {
                point(g[now].pos);
                type[g[now].pos]=g[now].be;
                point(g[now].pos);
            }
            else type[g[now].pos]=g[now].be;
            now--;    
        }
        if(dfn[e[i].l]>dfn[e[i].r]) swap(e[i].l,e[i].r);
        path(L,e[i].l);
        path(R,e[i].r);
        lca=get_lca(e[i].l,e[i].r);
        point(lca);
        ans[e[i].id]=tmp;
        point(lca);
        L=e[i].l; R=e[i].r;
        //printf("%d %d:",e[i].l,e[i].r);
        //printf("%I64d\n",tmp);
    }
    for(int i=1;i<=cnt;i++) 
    out(ans[i]),puts("");
}
int main()
{
    init();
    dfs1(1);
    dfs2(1,1);
    sort(e+1,e+cnt+1);
    solve();
}

 

树上分块比dfs序分块还要慢?

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<set>
#include<ctime>
#include<queue>
#include<cmath>
#include<algorithm>
#define inf 1000000000
#define ll long long
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
    return x*f;
}
ll ans,res[100005];
int bin[20];
int n,m,Q,ind,cnt,top;
int blo,blonum;
ll V[100005],W[100005],C[100005],pre[100005];
int fa[100005][17];
int last[100005],q[100005],deep[100005],belong[100005],dfn[100005];
int num[100005];
bool vis[100005];
struct edge{int to,next;}e[200005];
struct query{int x,y,t,id;}b[100005];
struct change{int x,y,t,pre;}c[100005];
bool operator<(query a,query b)
{
    if(belong[a.x]==belong[b.x]&&belong[a.y]==belong[b.y])return a.t<b.t;
    else if(belong[a.x]==belong[b.x])return belong[a.y]<belong[b.y];
    else return belong[a.x]<belong[b.x];
}
void insert(int u,int v)
{
    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
    e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}
int dfs(int x)
{
    int size=0;
    dfn[x]=++ind;
    for(int i=1;i<=16;i++)
        if(deep[x]>=bin[i])
            fa[x][i]=fa[fa[x][i-1]][i-1];
        else break;
    for(int i=last[x];i;i=e[i].next)
        if(e[i].to!=fa[x][0])
        {
            deep[e[i].to]=deep[x]+1;
            fa[e[i].to][0]=x;
            size+=dfs(e[i].to);
            if(size>=blo)
            {
                blonum++;
                for(int k=1;k<=size;k++)
                    belong[q[top--]]=blonum;
                size=0;
            }
        }
    q[++top]=x;
    return size+1;
}
int lca(int x,int y)
{
    if(deep[x]<deep[y])swap(x,y);
    int t=deep[x]-deep[y];
    for(int i=0;bin[i]<=t;i++)
        if(bin[i]&t)
            x=fa[x][i];
    for(int i=16;i>=0;i--)
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    if(x==y)return x;
    return fa[x][0];
}
void reverse(int x)
{
    if(vis[x])ans-=W[num[C[x]]]*V[C[x]],num[C[x]]--;
    else num[C[x]]++,ans+=W[num[C[x]]]*V[C[x]];
    vis[x]^=1;
}
void change(int x,int y)
{
    if(vis[x])
    {
        reverse(x);
        C[x]=y;
        reverse(x);
    }
    else C[x]=y;
}
void solve(int x,int y)
{
    while(x!=y)
    {
        if(deep[x]>deep[y])reverse(x),x=fa[x][0];
        else reverse(y),y=fa[y][0];
    }
}
int main()
{
    bin[0]=1;
    for(int i=1;i<20;i++)bin[i]=bin[i-1]<<1;
    n=read();m=read();Q=read();
    blo=pow(n,2.0/3)*0.5;
    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 u=read(),v=read();
        insert(u,v);
    }
    for(int i=1;i<=n;i++)pre[i]=C[i]=read();
    dfs(1);
    while(top)belong[q[top--]]=blonum;
    int c1=0,c2=0;
      for(int i=1;i<=Q;i++)
    {
        int typ=read(),x=read(),y=read();
        if(!typ)
        {
            c1++;
            c[c1].x=x;c[c1].y=y;c[c1].pre=pre[x];pre[x]=y;
        }
        else 
        {
            c2++;
            if(dfn[x]>dfn[y])swap(x,y);
            b[c2].x=x;b[c2].y=y;b[c2].id=c2;b[c2].t=c1;
        }
    }
    sort(b+1,b+c2+1);
    for(int i=1;i<=b[1].t;i++)
        change(c[i].x,c[i].y);
    solve(b[1].x,b[1].y);
    int t=lca(b[1].x,b[1].y);
    reverse(t);res[b[1].id]=ans;reverse(t);
    for(int i=2;i<=c2;i++)
    {
        for(int j=b[i-1].t+1;j<=b[i].t;j++)
            change(c[j].x,c[j].y);
        for(int j=b[i-1].t;j>b[i].t;j--)
            change(c[j].x,c[j].pre);
        solve(b[i-1].x,b[i].x);
        solve(b[i-1].y,b[i].y);
        int t=lca(b[i].x,b[i].y);
        reverse(t);res[b[i].id]=ans;reverse(t);
    }
    for(int i=1;i<=c2;i++)
        printf("%lld\n",res[i]);
    return 0;
}

 

以上是关于WC2013 糖果公园的主要内容,如果未能解决你的问题,请参考以下文章

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

WC2013 糖果公园 - 树上莫队

WC2013 糖果公园

[bzoj 3052][wc2013]糖果公园

BZOJ 3052: [wc2013]糖果公园 | 树上莫队

[WC2013]糖果公园