树上(带修改)莫队算法-- bzoj4129 && bzoj3757

bzoj3757似乎因为版权挂了
首先,我们要熟悉序列莫队
然后考虑树上莫队
(l,r)lr(lca),(l,r)(L,R)
,(l,r)=ans(root,l) xor ans(root,r) ,这样正好去掉了 lca
那么我们这样考虑: (root,l)>(root,L)
继续观察发现, (root,l)>(root,L)(l,L)
(root,root),lca
这样我们就可以很方便的上莫队算法了
关于树分块:
据说用王室联邦的分块会更快,我偷懒用了 dfs 序分块,反正复杂度一样
关于修改:
我们按 n23 分块,排序的时候左端点的块为第一关键字,右端点块为第二关键字,时间为第三关键字,
这样复杂度是 O((N+Q)53)
bzoj 3757

//Code by liuchenrui
#include<bits/stdc++.h>
const int N=50010,P=300;
using namespace std;
inline void splay(int &v){
    v=0;char c=0;int p=1;
    while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();}
    while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();}
    v*=p;
}
int to[N*2],nxt[N*2],fir[N],sz,a[N],Ans[N*2],sub[N],tot,dep[N],tt[N][17];
void add(int x,int y){
    nxt[++sz]=fir[x],fir[x]=sz,to[sz]=y;
}
void dfs(int x,int fa){
    tt[x][0]=fa;sub[x]=++tot;dep[x]=dep[fa]+1;
    for(int i=1;i<=16;i++){
        tt[x][i]=tt[tt[x][i-1]][i-1];
    }
    for(int u=fir[x];u;u=nxt[u]){
        if(to[u]!=fa){
            dfs(to[u],x);
        }
    }
}
int lca(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    for(int i=16;~i;i--){
        if(dep[tt[x][i]]>=dep[y]){
            x=tt[x][i];
        }
    }
    if(x==y)return x;
    for(int i=16;~i;i--){
        if(tt[x][i]!=tt[y][i]){
            x=tt[x][i];
            y=tt[y][i];
        }
    }
    return tt[x][0];
}
struct qr{
    int l,r,a,b,id;
    bool operator<(const qr&x)const{
        if(sub[l]/P!=sub[x.l]/P)return sub[l]<sub[x.l];
        return sub[r]<sub[x.r];
    }
}q[N*2];
int stk[N],top,t[N],ans,vis[N],n,Q;
void add(int x){
    t[a[x]]++;
    if(t[a[x]]==1)ans++;
}
void del(int x){
    t[a[x]]--;
    if(t[a[x]]==0)ans--;
}
void change(int x,int y){
    int _x=x,_y=y;
    top=0;
    while(x!=y){
        if(dep[x]>dep[y])stk[++top]=x,x=tt[x][0];
        else stk[++top]=y,y=tt[y][0];
    }
    for(int i=1;i<=top;i++){
        if(stk[i]==x)continue;
        vis[stk[i]]++;
        if(vis[stk[i]]&1)add(stk[i]);
        else del(stk[i]);
    }
}
int main(){
    splay(n),splay(Q);
    for(int i=1;i<=n;i++)splay(a[i]);
    for(int i=1;i<=n;i++){
        int x,y;splay(x),splay(y);
        if(x&&y)add(x,y),add(y,x);
    }
    dfs(1,0);
    for(int i=1;i<=Q;i++){
        splay(q[i].l),splay(q[i].r);
        splay(q[i].a),splay(q[i].b);
        q[i].id=i;
    }
    sort(q+1,q+Q+1);
    int l=1,r=1;
    for(int i=1;i<=Q;i++){
        change(l,q[i].l);l=q[i].l;
        change(r,q[i].r);r=q[i].r;
        add(lca(l,r));
        if(t[q[i].a]&&t[q[i].b]&&q[i].a!=q[i].b)Ans[q[i].id]=ans-1;
        else Ans[q[i].id]=ans;
        del(lca(l,r));
    }
    for(int i=1;i<=Q;i++){
        printf("%d\n",Ans[i]);
    }
}

bzoj4129

//Code by liuchenrui
#include<bits/stdc++.h>
const int N=50010,P=1300,P2=233;
using namespace std;
inline void splay(int &v){
    v=0;char c=0;int p=1;
    while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();}
    while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();}
    v*=p;
}
int to[N*2],nxt[N*2],fir[N],sz,a[N],Ans[N];
int sub[N],tot,dep[N],tt[N][18],_a[N],isq[N],m;
int stk[N],top,vis[N],n,Q,f[N],t[N],s[N];
void add(int x,int y){
    nxt[++sz]=fir[x],fir[x]=sz,to[sz]=y;
}
void dfs(int x,int fa){
    tt[x][0]=fa;sub[x]=++tot;dep[x]=dep[fa]+1;
    for(int i=1;i<=17;i++){
        tt[x][i]=tt[tt[x][i-1]][i-1];
    }
    for(int u=fir[x];u;u=nxt[u]){
        if(to[u]!=fa){
            dfs(to[u],x);
        }
    }
}
int lca(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    for(int i=17;~i;i--){
        if(dep[tt[x][i]]>=dep[y]){
            x=tt[x][i];
        }
    }
    if(x==y)return x;
    for(int i=17;~i;i--){
        if(tt[x][i]!=tt[y][i]){
            x=tt[x][i];
            y=tt[y][i];
        }
    }
    return tt[x][0];
}
namespace ans{
    int t[N],blo[N],l[N],r[N],bel[N],cnt;
    int add(int x){
        x=::a[x];
        t[x]++;
        if(t[x]==1)blo[bel[x]]++;
    }
    int del(int x){
        x=::a[x];
        t[x]--;
        if(t[x]==0)blo[bel[x]]--;
    }
    int getans(){
        for(int i=1;i<=cnt;i++){
            if(blo[i]!=r[i]-l[i]+1){
                for(int j=l[i];j<=r[i];j++){
                    if(!t[j])return j;
                }
            }
        }
    }
    void init(){
        int p=0;
        for(int i=0;i<=::n+1;i++){
            if(i/P2+1!=p){
                p=i/P2+1;
                l[++cnt]=i;
                r[cnt-1]=i-1;
            }
            bel[i]=cnt;
        }
        r[cnt]=n+1;
    }
}
struct qr{
    int l,r,v,id;
    bool operator<(const qr&x)const{
        if(sub[l]/P!=sub[x.l]/P)return sub[l]<sub[x.l];
        if(sub[r]/P!=sub[x.r]/P)return sub[r]<sub[x.r];
        return v<x.v;
    }
}q[N];
void change(int x,int y){
    int _x=x,_y=y;
    top=0;
    while(x!=y){
        if(dep[x]>dep[y])stk[++top]=x,x=tt[x][0];
        else stk[++top]=y,y=tt[y][0];
    }
    for(int i=1;i<=top;i++){
        if(stk[i]==x)continue;
        vis[stk[i]]++;
        if(vis[stk[i]]&1)ans::add(stk[i]);
        else ans::del(stk[i]);
    }
}
int main(){
    splay(n),splay(Q);
    for(int i=1;i<=n;i++){
        splay(a[i]);
        if(a[i]>n+1)a[i]=n+1;
    }
    for(int i=1;i<n;i++){
        int x,y;splay(x),splay(y);
        add(x,y),add(y,x);
    }
    dfs(1,0);
    int cnt=0;
    memcpy(_a,a,sizeof a);
    for(int i=1;i<=Q;i++){
        int op;splay(op);
        if(op){
            splay(q[++m].l),splay(q[m].r);
            q[m].v=cnt;q[m].id=i;
            isq[i]=1;
        }
        else{
            splay(f[++cnt]);
            s[cnt]=_a[f[cnt]];
            splay(t[cnt]);
            if(t[cnt]>n+1)t[cnt]=n+1;
            _a[f[cnt]]=t[cnt];
        }
    }
    sort(q+1,q+m+1);
    ans::init();
    int l=1,r=1,tim=0;;
    for(int i=1;i<=m;i++){
        change(l,q[i].l);l=q[i].l;
        change(r,q[i].r);r=q[i].r;
        while(tim<q[i].v){
            ++tim;
            if(vis[f[tim]]&1)ans::del(f[tim]);
            a[f[tim]]=t[tim];
            if(vis[f[tim]]&1)ans::add(f[tim]);
        }
        while(tim>q[i].v){
            if(vis[f[tim]]&1)ans::del(f[tim]);
            a[f[tim]]=s[tim];
            if(vis[f[tim]]&1)ans::add(f[tim]);
            --tim;
        }
        ans::add(lca(l,r));
        Ans[q[i].id]=ans::getans();
        ans::del(lca(l,r));
    }
    for(int i=1;i<=Q;i++){
        if(isq[i]){
            printf("%d\n",Ans[i]);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值