• LUOGU P4074 [WC2013]糖果公园 (树上带修莫队)


    传送门

    解题思路

    树上带修莫队,搞了两天。。终于开O2+卡常大法贴边过了。。。bzoj上跑了183s。。其实就是把树上莫队和带修莫队结合到一起,首先求出括号序,就是进一次出一次那种的,然后如果求两个点且两个点的LCA是这两个点的一个,那么树上的路径其实就是in[x]到in[y]。如果不是的话就是out[x]到in[y],且要加上lca,但这样太难统计,所以其实可以变成in[x]到in[y],然后直接特判。假如一段序列中既有一个点的in,又有一个点的out,那么其实就相当于没算,所以要记个vis数组表示这个东西该加还是该减,细节超级超级超级多。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<map>
    
    using namespace std;
    const int MAXN = 150005;
    typedef long long LL;
    
    inline int rd(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
        while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return f?x:-x;
    }
    
    inline void write(LL x){
        if(x>9) write(x/10);
        putchar(x%10+'0');
    }
    
    int n,m,Q,v[MAXN],w[MAXN],tot,head[MAXN],bl[MAXN],Qnum;
    int to[MAXN<<1],nxt[MAXN<<1],candy[MAXN],sizz,Qcnt,Ccnt;
    int in[MAXN],out[MAXN],node[MAXN<<1],num,cnt[MAXN];
    int fa[MAXN],son[MAXN],siz[MAXN],dep[MAXN],top[MAXN];
    LL ans[MAXN],Ans;
    bool vis[MAXN];
    map<pair<int,int>,int> mp;
    
    struct Data{
        int l,r,id,pre,lca;
    }q[MAXN];
    
    struct Change{
        int pos,val;
    }c[MAXN];
    
    inline void add(int bg,int ed){
        to[++tot]=ed,nxt[tot]=head[bg],head[bg]=tot;
    }
    
    void dfs1(int x,int f,int d){
        fa[x]=f,dep[x]=d,siz[x]=1;
        in[x]=++num,node[num]=x;
        register int maxson=-1,u;
        for(register int i=head[x];i;i=nxt[i]){
            u=to[i];if(u==f) continue;
            dfs1(u,x,d+1);
            siz[x]+=siz[u];
            if(siz[u]>maxson) {maxson=siz[u];son[x]=u;}
        }
        out[x]=++num,node[num]=x;
    }
    
    void dfs2(int x,int topf){
        top[x]=topf;
        if(!son[x]) return;
        dfs2(son[x],topf);register int u;
        for(register int i=head[x];i;i=nxt[i]){
            u=to[i];if(u==son[x] || u==fa[x]) continue;
            dfs2(u,u); 
        }
    }
    
    inline int LCA(int x,int y){
        while(top[x]!=top[y]){
            if(dep[top[x]]>=dep[top[y]]) x=fa[top[x]];
            else y=fa[top[y]];
        }
        return dep[x]>dep[y]?y:x;
    }
    
    inline bool cmp(Data A,Data B){
        if(bl[A.l]!=bl[B.l]) return bl[A.l]<bl[B.l];
        if(bl[A.r]!=bl[B.r]) return bl[A.r]<bl[B.r];
        return A.pre<B.pre;
    }
    
    inline void Add(int x){
        if(!vis[node[x]]){
            vis[node[x]]^=1;
            cnt[candy[node[x]]]++;
            Ans+=(LL)w[cnt[candy[node[x]]]]*v[candy[node[x]]];
    //        cout<<Ans<<endl;    
        }
        else {
            vis[node[x]]^=1;
            Ans-=(LL)w[cnt[candy[node[x]]]]*v[candy[node[x]]];
            cnt[candy[node[x]]]--;
        }
    }
    
    inline void Work(int x){
        if(vis[node[c[x].pos]]) {
            Ans-=(LL)w[cnt[candy[node[c[x].pos]]]]*v[candy[node[c[x].pos]]];
            cnt[candy[node[c[x].pos]]]--;cnt[c[x].val]++;
            Ans+=(LL)w[cnt[c[x].val]]*v[c[x].val];
        }     
        swap(c[x].val,candy[node[c[x].pos]]);
    }
    
    int main(){
        n=rd(),m=rd(),Q=rd();
        for(register int i=1;i<=m;i++) v[i]=rd();
        for(register int i=1;i<=n;i++) w[i]=rd();
        register int x,y,opt;
        for(register int i=1;i<n;i++){
            x=rd(),y=rd();
            add(x,y),add(y,x);
        }
        for(register int i=1;i<=n;i++) candy[i]=rd();
        dfs1(1,0,0);dfs2(1,1);register int Lca;
        for(register int i=1;i<=Q;i++){
            opt=rd(),x=rd(),y=rd();
            if(opt==1){
                if(mp.count(make_pair(x,y))) Lca=mp[make_pair(x,y)];
                else {Lca=LCA(x,y);mp[make_pair(x,y)]=mp[make_pair(y,x)]=Lca;}
                if(in[x]>in[y]) swap(x,y);
                q[++Qcnt].l=in[x],q[Qcnt].r=in[y],q[Qcnt].id=Qcnt,q[Qcnt].pre=Ccnt,q[Qcnt].lca=in[Lca];
            }
            else {c[++Ccnt].pos=in[x];c[Ccnt].val=y;}
        }
        sizz=pow(n,Ccnt?0.6:0.5);
        for(register int i=1;i<=n;i++) bl[i]=i/sizz+1;
    //    for(int i=1;i<=Qcnt;i++) cout<<q[i].l<<" "<<q[i].r<<endl;
        sort(q+1,q+1+Qcnt,cmp);
    //    for(int i=1;i<=Qcnt;i++) cout<<q[i].l<<" "<<q[i].r<<" "<<q[i].id<<endl;
        register int L=q[1].l,R=q[1].l-1,now=0;
        for(register int i=1;i<=Qcnt;i++){
            while(L<q[i].l) {Add(L);L++;}
            while(L>q[i].l) {L--;Add(L);}
            while(R<q[i].r) {R++;Add(R);}
            while(R>q[i].r) {Add(R);R--;}
            while(now<q[i].pre) {now++;Work(now);}
            while(now>q[i].pre) {Work(now);now--;}
            if(q[i].lca!=q[i].l) Add(q[i].l);
            if(q[i].lca!=q[i].l && q[i].lca!=q[i].r) Add(q[i].lca);
            ans[q[i].id]=Ans;
            if(q[i].lca!=q[i].l) Add(q[i].l);
            if(q[i].lca!=q[i].l && q[i].lca!=q[i].r) Add(q[i].lca);
        }
        for(register int i=1;i<=Qcnt;i++) write(ans[i]),puts("");
        return 0;
    }
    
    /*
    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
    
    0 2 1
    1 1 2
    1 4 2
    */
    View Code
  • 相关阅读:
    盘点黑客攻击途径:最常用的7个策略及简单的防护方法
    python 小技巧
    vi 使用方法
    Mac下添加环境变量(一劳永逸)
    增强for循环
    十大排序算法
    java中break、continue、return作用
    Mac zsh中所有命令失效
    Mac 每次都要执行source ~/.bash_profile 后,配置的环境变量才生效
    Mac下添加环境变量
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/9691516.html
Copyright © 2020-2023  润新知