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

10 篇文章 0 订阅
6 篇文章 0 订阅

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

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
    }
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值