bzoj4025 二分图

Posted miracevin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4025 二分图相关的知识,希望对你有一定的参考价值。

其实直接lct完事了。。。

但是太暴力不好看。。。

 

每个边存在于一个时间区间

对于每个时间区间都有询问

线段树分治!

dfs最后扫一遍

并查集按秩合并!

奇环?

并查集树上每个边维护这个点到并查集父亲节点在真实树中的距离奇偶性

发现,这个奇偶性可以直接异或的(可以认为一条边走过两次就是没有走过)

所以直接更新即可。

用栈维护事情,连接两个点或者出现了奇环(这个只第一次放进去即可)

代码:

O(nlog^2n)但是比lct常数小

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define mid ((l+r)>>1)
#define numb (ch^‘0‘)
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch==-)&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=100000+5;
const int M=200000+5;
int n,m,T;
struct node{
    int x,y;
}b[M];
vector<int>mem[4*N];
int fa[N];
int sz[N];
int dis[N];
int fin(int x){
    return fa[x]==x?x:fin(fa[x]);
}
int dist(int x){
    return fa[x]==x?dis[x]:dis[x]^dist(fa[x]);
}
void upda(int x,int l,int r,int L,int R,int id){
    if(L<=l&&r<=R){
        mem[x].push_back(id);
        return;
    }
    if(L<=mid) upda(x<<1,l,mid,L,R,id);
    if(mid<R) upda(x<<1|1,mid+1,r,L,R,id);
}
bool fl;//is or not 
struct event{
    int id;
    int chan,to;
}sta[M];
int top;
void dfs(int x,int l,int r){
    int st=top;
    for(reg i=0;i<(int)mem[x].size();++i){
        int k1=fin(b[mem[x][i]].x),k2=fin(b[mem[x][i]].y);
        if(k1!=k2){
            if(sz[k1]>sz[k2]) swap(k1,k2);
            
            fa[k1]=k2;
            sz[k2]+=sz[k1];
            dis[k1]=dist(b[mem[x][i]].x)^dist(b[mem[x][i]].y)^1;
            
            sta[++top].id=mem[x][i];
            sta[top].chan=k1,sta[top].to=k2;
            
        }else if(fl){
            if((dist(b[mem[x][i]].x)^dist(b[mem[x][i]].y))==0){
                fl=false;
                ++top;
                sta[top].id=-1;
                sta[top].chan=0;
                sta[top].to=0;
            }
        }
    }
    if(l==r){
        puts(fl?"Yes":"No");
    }else{
        dfs(x<<1,l,mid);
        dfs(x<<1|1,mid+1,r);
    }
    while(top!=st){
        if(sta[top].id==-1){
            fl=true;
        }else{
            sz[sta[top].to]-=sz[sta[top].chan];
            fa[sta[top].chan]=sta[top].chan;
            dis[sta[top].chan]=0;
        }
        --top;
    }
}
int main(){
    rd(n);rd(m);rd(T);
    for(reg i=1;i<=n;++i) fa[i]=i,dis[i]=0,sz[i]=1;
    int l,r;
    for(reg i=1;i<=m;++i){
        rd(b[i].x);rd(b[i].y);
        rd(l);rd(r);
        ++l;//warning !!!
        if(l<=r)upda(1,1,T,l,r,i);
    }
    fl=true;
    dfs(1,1,T);
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/2/10 20:59:09
*/

总结:
1.时间区间存在,可以想到线段树分治

2.并查集的维护距离的奇偶性的xor有点trick!

 

 

(这个题也可以对时间分治:[L,R]对于横跨[L,R]的边,拆成两个,分治下去。

但是如果到L=R的时候才停止的话,每个边拆成T个,就TLE了

发现,如果对于[l,r],如果一个边全程都出现在[l,r]中的话,那么就先加进去,就不拆开往下递归了

显然也是正确的

这样,每个边拆成log(T)份(类似线段树)

需要删除,并查集按秩合并(dis也是要维护的)

复杂度:O(mlog(T)log(N))


以上是关于bzoj4025 二分图的主要内容,如果未能解决你的问题,请参考以下文章

[bzoj4025]二分图_LCT

BZOJ4025 二分图

bzoj4025: 二分图(留坑后填)

BZOJ 4025 二分图(时间树+并查集)

bzoj4025 二分图

[BZOJ4025]二分图(线段树分治,并查集)