BZOJ 3052 WC2013 糖果公园 带修改树上莫队

题目大意:给定一棵树,每个点有一个颜色,提供两种操作:

1.询问两点间路径上的Σv[a[i]]*w[k],其中a[i]代表这个点的颜色,k表示这个点是这种颜色第k次出现

2.修改某个点的颜色

VfleaKing的题解见 http://vfleaking.blog.163.com/blog/static/174807634201311011201627/

带修改莫队上树……如果不带修改就正常搞就好了

如果带修改的话,令块的大小为n^(2/3)

将询问排序时第一键值为左端点所在块,第二键值为右端点所在块,第三键值为询问时间

然后将一个询问跳到下一个的时候先改链上的点,然后处理修改

这样最后可以保证最坏复杂度为O(n^(5/3)) 强行不到O(n^2)……

记住TLE不一定是常数大或者死循环 很可能是莫队写挂了 建议TLE的好好检查一下

另外推荐在半夜刷这道题……不然容易引起民粪……

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
namespace IStream{
    const int L=1<<15;
    char buffer[L];
    char *S,*T;
    inline char Get_Char()
    {
        if(S==T)
        {
            T=(S=buffer)+fread(buffer,1,L,stdin);
            if(S==T) return EOF;
        }
        return *S++;
    }
    inline int Get_Int()
    {
        int re=0;
        char c;
        do c=Get_Char(); while(c<'0'||c>'9');
        while(c>='0'&&c<='9')
            re=(re<<3)+(re<<1)+(c-'0'),c=Get_Char();
        return re;
    }
}

struct abcd{
    int to,next;
}table[M<<1];
struct query{
    int x,y,pos;
    bool operator < (const query &Y) const;
}queries[M];
struct modification{
    int x,from,to,pos;
}modifications[M];
int head[M],tot;
int n,m,q,B,end;bool flag;
int a[M],value[M],incuriosity[M];
int fa[M][20],belong[M],size[M],dpt[M],pos[M];
int cnt[M];bool v[M];long long now,ans[M];
bool query :: operator < (const query &Y) const
{
    if(flag)
    {
        if(belong[x]!=belong[Y.x])
            return belong[x]<belong[Y.x];
        if(belong[y]!=belong[Y.y])
            return belong[y]<belong[Y.y];
        return pos < Y.pos;
    }
    else
    {
        if(belong[x]!=belong[Y.x])
            return belong[x]<belong[Y.x];
        return ::pos[y] < ::pos[Y.y];
    }
}
void Add(int x,int y)
{
    table[++tot].to=y;
    table[tot].next=head[x];
    head[x]=tot;
}
void DFS(int x)
{
    int i;
    static int cnt=0,T=0;
    if(!fa[x][0]||size[belong[fa[x][0]]]==B)
        size[ belong[x]=++cnt ]++;
    else
        size[ belong[x]=belong[fa[x][0]] ]++;
    dpt[x]=dpt[fa[x][0]]+1;pos[x]=++T;
    for(i=head[x];i;i=table[i].next)
        if(table[i].to!=fa[x][0])
            fa[table[i].to][0]=x,DFS(table[i].to);
}
int LCA(int x,int y)
{
    int j;
    if(dpt[x]<dpt[y])
        swap(x,y);
    for(j=17;j>=0;j--)
        if(dpt[fa[x][j]]>=dpt[y])
            x=fa[x][j];
    if(x==y) return x;
    for(j=17;j>=0;j--)
        if(fa[x][j]!=fa[y][j])
            x=fa[x][j],y=fa[y][j];
    return fa[x][0];
}
void Change(int x)
{
    v[x]^=1;
    if(v[x]==1)
    {
        cnt[a[x]]++;
        if(cnt[a[x]]>=1)
            now+=(long long)value[a[x]]*incuriosity[cnt[a[x]]];
    }
    else
    {
        if(cnt[a[x]]>=1)
            now-=(long long)value[a[x]]*incuriosity[cnt[a[x]]];
        cnt[a[x]]--;
    }
}
void Change(modification temp,bool flag)
{
    if(flag) swap(temp.from,temp.to);
    a[temp.x]=temp.to;
    if(v[temp.x])
    {
        if(cnt[temp.from]>=1)
            now-=(long long)value[temp.from]*incuriosity[cnt[temp.from]];
        cnt[temp.from]--;
        cnt[temp.to]++;
        if(cnt[temp.to]>=1)
            now+=(long long)value[temp.to]*incuriosity[cnt[temp.to]];
    }
}
int main()
{
    int i,j,x,y,p,temp,lca;
    cin>>n>>m>>q;
    for(i=1;i<=m;i++)
        value[i]=IStream::Get_Int();
    for(i=1;i<=n;i++)
        incuriosity[i]=IStream::Get_Int();
    for(i=1;i<n;i++)
    {
        x=IStream::Get_Int();
        y=IStream::Get_Int();
        Add(x,y);
        Add(y,x);
    }
    for(i=1;i<=n;i++)
        a[i]=IStream::Get_Int();
    temp=0;
    for(i=1;i<=q;i++)
    {
        p=IStream::Get_Int();
        x=IStream::Get_Int();
        y=IStream::Get_Int();
        if(p==1)
        {
            if(pos[x]>pos[y])
                swap(x,y);
            queries[++temp].pos=temp;
            queries[temp].x=x;
            queries[temp].y=y;
        }
        else
        {
            flag=1;
            modifications[++end].x=x;
            modifications[end].from=a[x];
            modifications[end].to=a[x]=y;
            modifications[end].pos=temp;
        }
    }
    q=temp;
    if(flag)
        B=static_cast<int>(pow(n,2.0/3.0)+1e-7);
    else
        B=static_cast<int>(sqrt(n)+1e-7);
    DFS(1);
    for(j=1;j<=17;j++)
        for(i=1;i<=n;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1];
    x=y=1;temp=end;

    sort(queries+1,queries+q+1);
    for(i=1;i<=q;i++)
    {
        lca=LCA(x,queries[i].x);
        for(j=x;j!=lca;j=fa[j][0]) Change(j);
        for(j=queries[i].x;j!=lca;j=fa[j][0]) Change(j);
        lca=LCA(y,queries[i].y);
        for(j=y;j!=lca;j=fa[j][0]) Change(j);
        for(j=queries[i].y;j!=lca;j=fa[j][0]) Change(j);
        lca=LCA(x=queries[i].x,y=queries[i].y);
        Change(lca);
        for(;temp>0   && modifications[temp].pos>=queries[i].pos ;temp--)
            Change(modifications[temp],1);
        for(;temp<end && modifications[temp+1].pos<queries[i].pos;temp++)
            Change(modifications[temp+1],0);

        ans[queries[i].pos]=now;

        Change(lca);
    }
    for(i=1;i<=q;i++)
    {
        #ifdef ONLINE_JUDGE
            printf("%lld\n",ans[i]);
        #endif
        #ifdef C_PoPoQQQ
            printf("%I64d\n",ans[i]);
        #endif
    }
}
时间: 2024-11-07 23:50:01

BZOJ 3052 WC2013 糖果公园 带修改树上莫队的相关文章

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

3052: [wc2013]糖果公园 Time Limit: 250 Sec  Memory Limit: 512 MBSubmit: 506  Solved: 189[Submit][Status] Description Input Output Sample Input Sample Input Sample Output 84 131 27 84 HINT 本来这道题想到了莫队算法,但是看到带修改就直接放弃了.结果看题解才发现带修改居然也能用莫队!!!之所以可以这样用,是因为修改的时间复

BZOJ 4129 Haruna’s Breakfast 带修改树上莫队+分块

题目大意:给定一棵树,每个点有一个非负点权,支持下列操作 1.修改某个点的点权 2.查询某条链上的mex 考虑链上不带修改的版本,我们可以用莫队+分块来搞(链接戳这里) 现在到了树上带修改,果断糖果公园 本来抱着逗比的心态写了一发结果1.4s过了 跟糖果公园的80s完全不成正比啊0.0 #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <

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

3052: [wc2013]糖果公园 Time Limit: 200 Sec  Memory Limit: 512 MB Submit: 892  Solved: 425 [Submit][Status][Discuss] Description Input Output Sample Input Sample Input Sample Output 84 131 27 84 HINT Source [Submit][Status][Discuss] 题解:bzoj 2120 和 bzoj 37

[BZOJ 3052] [wc2013] 糖果公园 【树上莫队】

题目链接:BZOJ - 3052 题目分析 这道题就是非常经典的树上莫队了,并且是带修改的莫队. 带修改的莫队:将询问按照 左端点所在的块编号为第一关键字,右端点所在的块为第二关键字,位于第几次修改之后为第三关键字 排序. 我们将块的大小设置在 n^(2/3) ,这样一共有 n^(1/3) 个块.最后算法的总复杂度会是 n^(5/3) . 每一次如何从上一个询问转移来呢? 假设上一个询问是 (lx, ly, lt) ,这次的询问是 (x, y, t) .t 代表是在第 t 次修改操作之后. 首先

[bzoj 3052][wc2013]糖果公园

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3052 [wc2013]糖果公园 Time Limit: 200 Sec  Memory Limit: 512 MBSubmit: 1213  Solved: 609[Submit][Status][Discuss] Description Input Output Sample Input Sample Input Sample Output 84 131 27 84 树上莫队,把树分块,

bzoj 2120: 数颜色(带修改的莫队算法)

2120: 数颜色 Time Limit: 6 Sec  Memory Limit: 259 MB Submit: 2908  Solved: 1130 [Submit][Status][Discuss] Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col.为了满足墨墨的要求,你知道你需

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

题意:链接 方法:莫队上树 解析: 首先先考虑个莫队的算法,树分块 然后怎么做呢? 可以设两个指针么,然后按一定的排序方式移动指针,使复杂度可过. 观察到这道题是100s的,n^2是GG的,但比n^2稍微小一点就不GG了, 所以排序的作用就体现了. 按照左端点所在块为第一关键字,右端点所在块为第二关键字出现时间为第三关键字排序. 一共有n的1/3次方个块,所以所有的询问的左右端点所在的块的取值最多之后n的2/3次方种,对于每一种,对时间的修改最多会从尾改到头,所以又多乘一个q,n,q同阶,所以总

BZOJ 2120: 数颜色 带修改的莫队算法 树状数组套主席树

https://www.lydsy.com/JudgeOnline/problem.php?id=2120 标题里是两种不同的解法. 带修改的莫队和普通莫队比多了个修改操作,影响不大,但是注意一下细节不要出现zz错误. 这道题修改的数量比较少可以写莫队,但是如果修改数量多或者是特别极限的数据大概是不行的吧. 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstrin

带修改的莫队算法学习小记

简介 莫涛大神创造出的离线询问算法的带修改版. 算法基础:需要掌握莫队算法,会打暴搜(暴力). 一个叫莫的双端队列. 只支持单点修改 操作方法 普通的不带修改的莫队算法要把每个询问带上两个关键字排序,现在待修改的莫队算法要带上三个关键字排序. 初始操作 fo(i,1,m) { scanf("%s%d%d",s,&k,&l); if (s[0]=='Q')a[++tot].l=k,a[tot].r=l,a[tot].x=num,a[tot].p=tot; else d[+