洛谷P4074 [WC2013]糖果公园(BZOJ3052)

树上莫队

洛谷题目传送门
BZOJ题目传送门

学了发树上莫队。

树上分块是按照王室联邦这道题来分的。

如果没有修改的话直接在树上跳就好了。现在有了修改操作,那么先和带修改莫队一样记一个 t ,每次询问前先还原到当前时间。

接下来和序列操作不一样的是移动两个端点。做法是开一个 f [ i ] 表示 i 是否在当前处理的路径上,当从 ( x 1 , y 1 ) 转移到 ( x 2 , y 2 ) 时,把 ( x 1 , x 2 ) ( y 1 , y 2 ) 路径上的点的 f 取反并更新答案(不包括 L C A )。

这么做为什么是对的呢?

S ( v , u ) 代表 v u 的路径上的结点的集合。用 r o o t 来代表根结点,用 l c a ( v , u ) 来代表 v , u 的最近公共祖先。那么 S ( v , u ) = S ( r o o t , v )   x o r   S ( r o o t , u )   x o r   l c a ( v , u ) 。其中 x o r 是集合的对称差,简单来说就是节点出现两次消掉。

l c a 很讨厌,于是再定义 T ( v , u ) = S ( r o o t , v )   x o r   S ( r o o t , u )

观察将 c u r V 移动到 t a r g e t V 前后 T ( c u r V , c u r U ) 变化:

T ( c u r V , c u r U ) = S ( r o o t , c u r V )   x o r   S ( r o o t , c u r U )

T ( t a r g e t V , c u r U ) = S ( r o o t , t a r g e t V )   x o r   S ( r o o t , c u r U )

取对称差:

T ( c u r V , c u r U )   x o r   T ( t a r g e t V , c u r U ) = ( S ( r o o t , c u r V )   x o r   S ( r o o t , c u r U ) )   x o r   ( S ( r o o t , t a r g e t V )   x o r   S ( r o o t , c u r U ) )

由于对称差的交换律、结合律:

T ( c u r V , c u r U )   x o r   T ( t a r g e t V , c u r U ) = S ( r o o t , c u r V )   x o r   S ( r o o t , t a r g e t V )

两边同时 x o r   T ( c u r V , c u r U )

T ( t a r g e t V , c u r U ) = T ( c u r V , c u r U )   x o r   S ( r o o t , c u r V )   x o r   S ( r o o t , t a r g e t V )

发现最后两项很爽……哇哈哈

T ( t a r g e t V , c u r U ) = T ( c u r V , c u r U )   x o r   T ( c u r V , t a r g e t V )

也就是说,更新的时候, x o r   T ( c u r V , t a r g e t V ) 就行了。

即,对 c u r V t a r g e t V 路径(除开 l c a ( c u r V , t a r g e t V ) )上的结点,将它们的存在性取反即可。

—By vfleaking

代码:

#include<cmath>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define F inline
using namespace std;
typedef long long LL;
struct edge{ int next,to; }ed[N<<1];
struct que{ int x,y,id,t; }q[N];
struct mod{ int x,y,nxt; }a[N];
int n,m,s,k,n1,n2,b,tp,p,nd,h[N],dep[N],fa[N][20];
int ha[N],stk[N],num[N],t[N],v[N],w[N],ti[N],c[N];
LL sum,ans[N]; bool f[N];
F char readc(){
    static char buf[100000],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    if (l==r) return EOF; return *l++;
}
F int _read(){
    int x=0,f=1; char ch=readc();
    while (!isdigit(ch)) { if (ch=='-') f=-1; ch=readc(); }
    while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
    return x*f;
}
F void writec(LL x){ if (x>9) writec(x/10); putchar(x%10+48); }
F void _write(LL x){ writec(x),putchar('\n'); }
#define addedge(x,y) ed[++k]=(edge){h[x],y},h[x]=k
F bool cmp(que x,que y){
    bool f1=num[x.x]==num[y.x],f2=num[x.y]==num[y.y];
    return num[x.x]<num[y.x]||(f1&&num[x.y]<num[y.y])||(f1&&f2&&x.t<y.t);
}
void dfs(int x){
    ti[x]=++p; int now=tp;
    for (int i=h[x],v;i;i=ed[i].next)
        if ((v=ed[i].to)!=fa[x][0]){
            fa[v][0]=x,dep[v]=dep[x]+1,dfs(v);
            if (tp-now>=b) for (nd++;tp!=now;) num[stk[tp--]]=nd; 
        }
    stk[++tp]=x;
}
F void Make(){
    for (int j=1;j<20;j++)
        for (int i=1;i<=n;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1];
}
F int LCA(int x,int y){
    if (dep[x]<dep[y]) swap(x,y);
    for (int j=19;~j;j--)
        if (dep[fa[x][j]]>=dep[y]) x=fa[x][j];
    if (x==y) return x;
    for (int j=19;~j;j--)
        if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
    return fa[x][0];
}
F void rvrs(int x){
    if (!f[x]) f[x]=true,t[c[x]]++,sum+=1ll*w[t[c[x]]]*v[c[x]];
    else f[x]=false,sum-=1ll*w[t[c[x]]]*v[c[x]],t[c[x]]--;
}
F void mdfy(int x,int y){
    if (!f[x]) c[x]=y; else rvrs(x),c[x]=y,rvrs(x);
}
F void srch(int x,int y){
    while (x!=y)
        if (dep[x]<dep[y]) rvrs(y),y=fa[y][0];
        else rvrs(x),x=fa[x][0];
}
int main(){
    n=_read(),m=_read(),s=_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,x,y;i<n;i++)
        x=_read(),y=_read(),addedge(x,y),addedge(y,x);
    for (int i=1;i<=n;i++) ha[i]=c[i]=_read();
    dep[1]=1,b=(int)pow(n,0.6),dfs(1),Make();
    for (int i=1;i<=s;i++){
        int f=_read(),x=_read(),y=_read();
        if (!f) a[++n2]=(mod){x,y,ha[x]},ha[x]=y;
        else{
            if (ti[x]>ti[y]) swap(x,y);
            q[++n1]=(que){x,y,n1,n2};
        }
    }
    sort(q+1,q+n1+1,cmp);
    for (int i=1;i<=q[1].t;i++) mdfy(a[i].x,a[i].y);
    srch(q[1].x,q[1].y); int lca=LCA(q[1].x,q[1].y);
    rvrs(lca),ans[q[1].id]=sum,rvrs(lca);
    for (int i=2,j;i<=n1;i++){
        for (j=q[i-1].t+1;j<=q[i].t;j++) mdfy(a[j].x,a[j].y);
        for (j=q[i-1].t;j>q[i].t;j--) mdfy(a[j].x,a[j].nxt);
        srch(q[i-1].x,q[i].x),srch(q[i-1].y,q[i].y);
        int l=LCA(q[i].x,q[i].y);
        rvrs(l),ans[q[i].id]=sum,rvrs(l);
    }
    for (int i=1;i<=n1;i++) _write(ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a1799342217/article/details/80356802