首页 > 其他 > 详细

线段树分治学习笔记

时间:2020-03-10 19:49:11      阅读:53      评论:0      收藏:0      [点我收藏+]

1.一种数据结构,一般用于有撤销操作,并且不好处理撤销的题目中。这个时候对时间建立线段树,将每个修改和询问插入对应时间内,对每个线段树节点进行处理就可以保证时间复杂度为 \( \O (nlogn) \) 。

2.例题

(1)

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

题意:给出n个点,m条边,每条边从时间l出现,r消失,求每个时间图是否是二分图。

题解:

二分图的判定可以通过判断奇环来搞,判奇环可以使用扩展域并查集。

进行线段树分治,将每条边插入对应时间的节点vector中,到了一个节点后使用可撤销并查集将所有该节点的的边处理了,递归结束时将边的贡献撤销即可。(使用一个栈记录每次操作前的状态)。

代码如下:

技术分享图片
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int k,n,m,fa[N],u[N],v[N],dep[N];
vector <int> ve[N<<1];
struct pigu
{
    int xp,shu;
    pigu(int x=0,int y=0)
    {
        shu=x;xp=y;
    }
};
inline int read()
{
    char c=getchar();
    int x=0,f=1;
    while(!isdigit(c)) {if(c==-) f=-1;c=getchar();}
    while(isdigit(c)) {x=(x<<3)+(x<<1)+c-0;c=getchar();}
    return x*f;
}
inline void insert(int now,int l,int r,int L,int R,int jia)
{
    if(l>=L&&r<=R)
    {
        ve[now].push_back(jia);
        return;
    }
    int mid=(l+r)>>1;
    if(L<=mid) insert(now<<1,l,mid,L,R,jia);
    if(R>=mid+1) insert(now<<1|1,mid+1,r,L,R,jia);
}
stack <pigu> st;
inline int find(int x)
{
    if(x==fa[x]) return x;
    return find(fa[x]);
}
inline void merge(int x,int y)
{
    if(x==y) return;
    if(dep[x]<dep[y]) swap(x,y);
    st.push(pigu(y,dep[x]==dep[y]));
    fa[y]=x;dep[x]+=(dep[x]==dep[y]);
}
inline void get_ans(int now,int l,int r)
{
    bool pan=0;
    int len=ve[now].size(),hu=st.size();
    for(int i=0;i<len;i++)
    {
        int fa1=find(u[ve[now][i]]),fa2=find(v[ve[now][i]]);
        if(fa1==fa2)
        {
            for(int j=l;j<=r;j++)
                cout<<"No\n";
            pan=1;
            break;
        }
        merge(find(u[ve[now][i]]+n),fa2);merge(find(v[ve[now][i]]+n),fa1);
    }
    if(pan==0)
    {
        int mid=(l+r)>>1;
        if(l==r) cout<<"Yes\n";
        else 
        {
            get_ans(now<<1,l,mid);
            get_ans(now<<1|1,mid+1,r);
        }
    }
    while(st.size()>hu)
    {
        dep[fa[st.top().shu]]-=st.top().xp;
        fa[st.top().shu]=st.top().shu;
        st.pop();
        
    }
}
int main()
{
    n=read();m=read();k=read();
    for(int i=1;i<=2*n;i++) fa[i]=i;
    for(int i=1,l,r;i<=m;i++)
    {
        u[i]=read();v[i]=read();l=read();r=read();
        if(l<r) insert(1,1,k,l+1,r,i);
    }
    get_ans(1,1,k);
}
View Code

线段树分治学习笔记

原文:https://www.cnblogs.com/betablewaloot/p/12458000.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!