【DS】线段树分治学习笔记

\(\circ\) 给你一堆操作,每个操作都有自己的影响时间,查询某一时间点的状态。

  • 线段树分治:按时间轴将修改保存到 \(\log\) 个区间里,将询问离线查询,时刻 \(t\) 的询问就是线段树上根节点走到 \([t,t]\) 后的数据结构。

\(\circ\) 给你一堆操作,查询一段时间内的状态。

  • 线段树分治:按时间轴将修改和查询都保存到 \(\log\) 个区间里,时刻 \(t\) 的修改影响线段树上根节点走到 \([t,t]\) 的各个区间,查询就是将这些区间的影响合并。

适用范围:需要的数据结构不支持删除,但是能快速撤销,如 线性基,李超线段树,并查集 等。

P5787 二分图 /【模板】线段树分治

这属于上面的第一种情况。判断二分图用扩展域并查集(注意不能路径压缩)。

点击查看代码
#define pb push_back
const int N=1e5+10;
typedef pair<int,int> pr;

int n,m,k;
int fa[N<<1],siz[N<<1];
vector<pr> q[N<<2];
bool vis[N<<2];

#define ls p<<1
#define rs p<<1|1

void modify(int p,int l,int r,int ql,int qr,int u,int v){
    if(ql<=l&&r<=qr)return q[p].pb({u,v}),void();
    int mid=(l+r)>>1;
    if(ql<=mid)modify(ls,l,mid,ql,qr,u,v);
    if(qr>mid)modify(rs,mid+1,r,ql,qr,u,v);
}
int fnd(int x){//要支持撤销操作,不能路径压缩
    return fa[x]==x?x:fnd(fa[x]);
}
void undo(vector<pr> a){//撤销
    for(pr tmp:a){
        siz[tmp.first]-=siz[tmp.second];
        fa[tmp.second]=tmp.second;
    }
}
void query(int p,int l,int r){
    vector<pr> upd;
    if(vis[p]){
        for(pr tmp:q[p]){
            int u=fnd(tmp.first),v=fnd(tmp.second),
                uu=fnd(tmp.first+n),vv=fnd(tmp.second+n);
            if(u==v){vis[p]=0;break;}
            if(siz[u]<siz[vv])swap(u,vv);
            if(siz[v]<siz[uu])swap(v,uu);
            fa[vv]=u,siz[u]+=siz[vv];fa[uu]=fa[v],siz[v]+=siz[uu];
            upd.pb({u,vv}),upd.pb({v,uu});
        }
    }
    if(l==r)return vis[p]?printf("Yes\n"):printf("No\n"),undo(upd),void();
    vis[ls]=vis[rs]=vis[p];
    int mid=(l+r)>>1;
    query(ls,l,mid),query(rs,mid+1,r);
    undo(upd);
}

int main(){
    read(n),read(m),read(k);
    for(int i=1;i<=n*2;++i)fa[i]=i,siz[i]=1;
    int u,v,l,r;
    while(m--){
        read(u),read(v),read(l),read(r);
        modify(1,1,k,l+1,r,u,v);
    }vis[1]=1,query(1,1,k);
    return 0;
}

P4585 [FJOI2015]火星商店问题

这属于上面的第二种情况。求异或最大值用可持久化 trie,对于每个区间的修改建出 trie 然后更新包含该区间的询问。

点击查看代码
#define pb push_back
const int N=1e5+10;
typedef pair<int,int> pr;

int n,m;
struct qry{int l,r,x,id;};
vector<qry> q[N<<2];
vector<pr> upd[N<<2];
int ans[N];

struct trie{
    int cnt=0,rt[N],son[N<<5][2],siz[N<<5];
    void clear(){memset(son,0,cnt+10),memset(siz,0,cnt+10);cnt=0;}
    void insert(int &cur,int pre,int val,int bit=16){
        cur=++cnt;
        son[cur][0]=son[pre][0],son[cur][1]=son[pre][1],siz[cur]=siz[pre]+1;
        if(bit==-1)return;
        int id=(val>>bit)&1;
        insert(son[cur][id],son[pre][id],val,bit-1);
    }
    int query(int l,int r,int val,int bit=16){
        if(bit==-1||!(siz[r]-siz[l]))return 0;
        int id=(val>>bit)&1,qwq=id^1;
        if(siz[son[r][qwq]]-siz[son[l][qwq]]>0)return (1<<bit)+query(son[l][qwq],son[r][qwq],val,bit-1);
        return query(son[l][id],son[r][id],val,bit-1);
    }
}all,now;

#define ls p<<1
#define rs p<<1|1
void modify(int p,int l,int r,int pos,pr v){
    upd[p].pb(v);
    if(l==r)return;
    int mid=(l+r)>>1;
    if(pos<=mid)modify(ls,l,mid,pos,v);
    else modify(rs,mid+1,r,pos,v);
}
void query(int p,int l,int r,int ql,int qr,qry v){
    if(ql<=l&&r<=qr)return q[p].pb(v),void();
    int mid=(l+r)>>1;
    if(ql<=mid)query(ls,l,mid,ql,qr,v);
    if(qr>mid)query(rs,mid+1,r,ql,qr,v);
}
void calc(int p){
    now.clear();sort(upd[p].begin(),upd[p].end());
    //按编号顺序加入方便查询
    int pre=0;
    for(pr tmp:upd[p]){
        now.insert(now.rt[tmp.first],now.rt[pre],tmp.second);
        pre=tmp.first;
    }
    for(qry tmp:q[p]){
        int l=lower_bound(upd[p].begin(),upd[p].end(),make_pair(tmp.l,0))-upd[p].begin();
        int r=lower_bound(upd[p].begin(),upd[p].end(),make_pair(tmp.r,114514))-upd[p].begin()-1;
        if(r<0)continue;
        l=l?upd[p][l-1].first:0,r=upd[p][r].first;
        ans[tmp.id]=max(ans[tmp.id],now.query(now.rt[l],now.rt[r],tmp.x));
    }
}
void solve(int p,int l,int r){
    calc(p);
    if(l==r)return;
    int mid=(l+r)>>1;
    solve(ls,l,mid);solve(rs,mid+1,r);
}

int main(){
    read(n),read(m);memset(ans,-1,sizeof ans);
    for(int i=1,x;i<=n;++i)read(x),all.insert(all.rt[i],all.rt[i-1],x);
    int now=0,op,l,r,d,x;
    for(int i=1;i<=m;++i){
        read(op);now+=!op;
        if(!op){
            read(d),read(x);
            modify(1,0,m,now,{d,x});
        }else {
            read(l),read(r),read(x),read(d);
            ans[i]=all.query(all.rt[l-1],all.rt[r],x);
            if(d)query(1,0,m,max(1,now-d+1),now,(qry){l,r,x,i});
        }
    }solve(1,0,m);
    for(int i=1;i<=m;++i)if(ans[i]!=-1)printf("%d\n",ans[i]);
    return 0;
}
posted @ 2022-10-19 13:12  RuntimeErr  阅读(14)  评论(0编辑  收藏  举报