bzoj3052 [wc2013]糖果公园 (树上带修改莫队)

bzoj3052 [wc2013]糖果公园

原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3052

题意:
(权限题贴题面)
bzoj3052 [wc2013]糖果公园 (树上带修改莫队)_第1张图片

bzoj3052 [wc2013]糖果公园 (树上带修改莫队)_第2张图片
这里写图片描述
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

数据范围

bzoj3052 [wc2013]糖果公园 (树上带修改莫队)_第3张图片
bzoj3052 [wc2013]糖果公园 (树上带修改莫队)_第4张图片

题解:

关于树上莫队转序列莫队:
遍历一棵树记录in,out得到一个括号序:
例如:
bzoj3052 [wc2013]糖果公园 (树上带修改莫队)_第5张图片

得到:
1 2 3 3 2 4 10 8 8 5 5 10 4 6 7 7 9 9 6 1

对于两个点u,v的链: (in[u] < in[v])
1.u是v的祖先:从in[u]到in[v],中间出现两次的(in,out)的消掉,剩下的序列。
2.u不是v的祖先:从out[u]到in[v],中间出现两次的(in,out)的消掉,剩下的序列。
这个出现两次消掉就开个数序记录一下。

带修莫队见此

于是这道题就是裸题。

今天卡了一发评测,不仅第一次交没过(还是因为cmp写错TLE),还手滑连续交了两发TLE,还用的是别人的号233。
不远就听见Mercer在那骂:哪个sb交糖果公园还交两发。
以为没被认出来正在那庆幸,就被wys揭发了…

代码:

#include
#include
#include
#include
#include
#define LL long long
using namespace std;
const int N=200005;
const int MXN=1000006;
const int P=17;
int n,m,q,col[N],st[N],cnt[N],V[N],W[N],head[N],to[2*N],nxt[2*N],num=0,blo;
int qs=0,md=0;
LL sum[N],ans[N],now=0,vis[2*N];
int dep[N],anc[N][P+3],in[N],out[N],seq[2*N],inc=0;
void build(int u,int v)
{
    num++;
    to[num]=v;
    nxt[num]=head[u];
    head[u]=num;
}
void dfs(int u,int f)
{
    inc++; seq[inc]=u; in[u]=inc;
    dep[u]=dep[f]+1;
    anc[u][0]=f;
    for(int i=1;i1]][i-1];

    for(int i=head[u];i;i=nxt[i])
    {   
        int v=to[i];
        if(v==f) continue;
        dfs(v,u);
    }
    inc++; seq[inc]=u; out[u]=inc;
}
struct Query
{
    int L,R,t,id,pos;
}Q[N];
struct Modify
{
    int pos,pre,nxt;
}M[N];
int getlca(int u,int v)
{
    if(dep[u]int d=dep[u]-dep[v];
    for(int i=0;d;d>>=1,i++) if(d&1) u=anc[u][i];
    if(u==v) return u;
    for(int i=P-1;i>=0;i--)
    if(anc[u][i]!=anc[v][i]) {u=anc[u][i]; v=anc[v][i]; }
    return anc[u][0];
}
int getb(int x) {return (x-1)/blo+1;}
bool cmp(const Query &A,const Query &B)
{
    if(getb(A.L)!=getb(B.L)) return A.Lelse if(getb(A.R)!=getb(B.R)) return A.Relse return A.tint pos,int opt)
{ 
    int u=seq[pos];  
    now-=1LL*sum[cnt[col[u]]]*1LL*V[col[u]];
    vis[u]^=1; if(vis[u]) cnt[col[u]]++; else cnt[col[u]]--;

    now+=1LL*sum[cnt[col[u]]]*1LL*V[col[u]];
}
void change(int tim,int opt)
{
    int pre=M[tim].pre; int nxt=M[tim].nxt; int pos=M[tim].pos;
    if(vis[pos])
    {
        now-=1LL*sum[cnt[col[pos]]]*1LL*V[col[pos]]; cnt[col[pos]]--;
        now+=1LL*sum[cnt[col[pos]]]*1LL*V[col[pos]]; 
        col[pos]= opt>0? nxt:pre;
        now-=1LL*sum[cnt[col[pos]]]*1LL*V[col[pos]]; cnt[col[pos]]++;
        now+=1LL*sum[cnt[col[pos]]]*1LL*V[col[pos]];
    }
    else col[pos]= opt>0? nxt:pre;  
}
void moto()
{
    int lf=1,rg=0,cur=0; 
    for(int i=1;i<=qs;i++)
    {
        while(rg1);
        while(lf>Q[i].L) modify(--lf,1);
        while(rg>Q[i].R) modify(rg--,-1);
        while(lf1);
        while(cur1);
        while(cur>Q[i].t) change(cur--,-1);
        int lca=Q[i].pos; 
        ans[Q[i].id]=now;
        if(lca)
        {
            ans[Q[i].id]-=1LL*sum[cnt[col[lca]]]*1LL*V[col[lca]]; 
            ans[Q[i].id]+=1LL*sum[cnt[col[lca]]+1]*1LL*V[col[lca]]; 
        }
    }    
}
int main()
{
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=m;i++) scanf("%d",&V[i]);
    for(int i=1;i<=n;i++) scanf("%d",&W[i]);
    sum[0]=0; for(int i=1;i<=n;i++) sum[i]=sum[i-1]+1LL*W[i];
    for(int i=1;iint u,v; scanf("%d%d",&u,&v);
        build(u,v); build(v,u);
    }
    for(int i=1;i<=n;i++) {scanf("%d",&col[i]); st[i]=col[i];}
    dfs(1,1); blo=(int)pow((double)inc,(double)2/3);
    for(int i=1;i<=q;i++)
    {
        int opt,x,y;
        scanf("%d%d%d",&opt,&x,&y);
        if(opt==0)
        {
            md++; M[md].pre=col[x]; M[md].pos=x;col[x]=y; M[md].nxt=y;
        }
        else
        {
            qs++; Q[qs].id=qs; Q[qs].t=md; 
            int lca=getlca(x,y);  if(dep[x]>dep[y]) swap(x,y);
            if(lca!=x) Q[qs].pos=lca; else Q[qs].pos=0;
            if(in[x]>in[y]) swap(x,y);
            Q[qs].R=in[y]; Q[qs].L=(out[x]>in[y])? in[x]:out[x];    
        }   
    }
    for(int i=1;i<=n;i++) col[i]=st[i];
    sort(Q+1,Q+qs+1,cmp);
    moto();
    for(int i=1;i<=qs;i++)
    printf("%lld\n",ans[i]);
    return 0;   
}

你可能感兴趣的:(&,图论,题解,莫队算法,带修改莫队,树上莫队)