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

传送门:bzoj3052


题解网上很多,具体做法其实本蒟蒻不是非常了解,还需复习


代码

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int tot,n,m,t,T,blo,blonum,pre[N];
int in[N],dfn,d[N],pos[N],Q[N],num[N],top;
ll w[N],v[N],c[N],ans,res[N];
int head[N],to[N<<2],nxt[N<<2],vis[N],f[N][17],bin[20];
struct query{int x,y,t,id;}asw[N];
struct change{int x,y,t,pre;}cg[N];

inline int read()
{
    char ch=getchar();int x=0,f=1;
    while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch<='9' && ch>='0'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*f;
}

inline void lk(int u,int v)
{
    to[++tot]=v;nxt[tot]=head[u];head[u]=tot;
    to[++tot]=u;nxt[tot]=head[v];head[v]=tot;
}

inline void swa(int &x,int &y){int t=x;x=y;y=t;}

bool cmp(query a,query b)
{
    if(pos[a.x]==pos[b.x]){
        if(pos[a.y]==pos[b.y]) return a.t<b.t;
        else return pos[a.y]<pos[b.y];
    } 
    else return pos[a.x]<pos[b.x];
}

inline int dfs(int x)
{
    int i,sz=0;
    in[x]=++dfn;
    for(i=1;i<=16;i++){
        if(bin[i]<=d[x]) f[x][i]=f[f[x][i-1]][i-1];
        else break;
    }
    for(i=head[x];i;i=nxt[i]){
        if(to[i]==f[x][0]) continue;
        f[to[i]][0]=x;d[to[i]]=d[x]+1; 
        sz+=dfs(to[i]);
        if(sz>=blo){
            blonum++;
            for(int k=1;k<=sz;k++) pos[Q[top--]]=blonum;
            sz=0;
        }
    }
    Q[++top]=x;
    return sz+1;
}

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

inline void change(int x,int y)
{
    if(vis[x]){
        reverse(x);
        c[x]=y;
        reverse(x);
    }
    else c[x]=y;
}

inline void solve(int x,int y)
{
    while(x!=y){
        if(d[x]>d[y])    reverse(x),x=f[x][0];
        else reverse(y),y=f[y][0];
    }
}

inline int LCA(int x,int y)
{
    int i;
    if(d[x]<d[y]) swa(x,y);
    int t=d[x]-d[y];
    for(i=0;bin[i]<=t;i++){
        if(bin[i]&t) x=f[x][i];
    }
    for(i=16;i>=0;i--)
       if(f[x][i]!=f[y][i])
         x=f[x][i],y=f[y][i];
    if(x==y) return x;
    return f[x][0];
}

int main(){
    int i,j,u,des;
    bin[0]=1;for(i=1;i<20;i++) bin[i]=(bin[i-1]<<1); 
    n=read();m=read();T=read();
    blo=pow(n,2.0/3)*0.5; 
    for(i=1;i<=m;i++) v[i]=read();
    for(i=1;i<=n;i++) w[i]=read();
    for(i=1;i<n;i++){u=read();des=read();lk(u,des);} 
    for(i=1;i<=n;i++) pre[i]=c[i]=read();
    dfs(1);
    while(top) pos[Q[top--]]=blonum;
    int c1=0,c2=0;
    for(i=1;i<=T;i++) {
       int op=read(),x=read(),y=read();
       if(!op)  {c1++;cg[c1].x=x,cg[c1].y=y,cg[c1].pre=pre[x];pre[x]=y;}
       else{if(in[x]>in[y]) swa(x,y);c2++;asw[c2].x=x,asw[c2].y=y,asw[c2].id=c2;asw[c2].t=c1;}
    }
    sort(asw+1,asw+c2+1,cmp);
    for(i=1;i<=asw[1].t;i++) change(cg[i].x,cg[i].y);
    solve(asw[1].x,asw[1].y);
    t=LCA(asw[1].x,asw[1].y);
    reverse(t);res[asw[1].id]=ans;reverse(t);
    for(i=2;i<=c2;i++){
        for(j=asw[i-1].t+1;j<=asw[i].t;j++) change(cg[j].x,cg[j].y);
        for(j=asw[i-1].t;j>asw[i].t;j--) change(cg[j].x,cg[j].pre);
        solve(asw[i-1].x,asw[i].x);
        solve(asw[i-1].y,asw[i].y);
        t=LCA(asw[i].x,asw[i].y);
        reverse(t);res[asw[i].id]=ans;reverse(t); 
    }
    for(i=1;i<=c2;i++) printf("%lld\n",res[i]);
    return 0;
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值