bzoj4025: 二分图

这题想不出来。

不浪费时间了。

以后找时间填。

 --------------------update---------------

就是判奇环咯

然而LCT我搞不出来。。

是因为对于当前的最大生成树,新时间加入的边可能是比前面最大生成树里最小边要大,然后就要找到最大生成树里最小的边。。这样要化边为点我萎了还是写不出来你们去%吧

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
using namespace std;

struct node
{
    int x,y;
}a[210000];
 
struct heap_st
{
    int st,ed,id;
    friend bool operator>(heap_st n1,heap_st n2){return n1.st>n2.st;}
};priority_queue<heap_st,vector<heap_st>,greater<heap_st> >A;
struct heap_ed
{
    int ed,id;
    friend bool operator>(heap_ed n1,heap_ed n2){return n1.ed>n2.ed;}
};priority_queue<heap_ed,vector<heap_ed>,greater<heap_ed> >B;
struct heap_mt
{
    int ed,id;
    friend bool operator>(heap_mt n1,heap_mt n2){return n1.ed<n2.ed;}
};priority_queue<heap_mt,vector<heap_mt>,greater<heap_mt> >C;
 
 
//---------edge&&heap---------------
 

struct LCT
{
    int f,c,son[2];
    bool fz;
}tr[210000];
void yu(int n){for(int i=1;i<=n;i++)tr[i].c=1,tr[i].fz=false;}
void update(int x)
{
    int lc=tr[x].son[0],rc=tr[x].son[1];
    tr[x].c=tr[lc].c+tr[rc].c+1;
}
void reverse(int x)
{
    tr[x].fz=false;
    swap(tr[x].son[0],tr[x].son[1]);
    int lc=tr[x].son[0],rc=tr[x].son[1];
    tr[lc].fz=1-tr[lc].fz;
    tr[rc].fz=1-tr[rc].fz;
}
void rotate(int x,int w)
{
    int f=tr[x].f,ff=tr[f].f;
    int R,r;
    
    R=f;r=tr[x].son[w];
    tr[R].son[1-w]=r;
    if(r!=0)tr[r].f=R;
    
    R=ff;r=x;
          if(tr[R].son[0]==f)tr[R].son[0]=r;
    else if(tr[R].son[1]==f)tr[R].son[1]=r;
    tr[r].f=R;
    
    R=x;r=f;
    tr[R].son[w]=r;
    tr[r].f=R;
    
    update(f);
    update(x);
}
bool isroot(int x)
{
    if(tr[x].f!=0&&(tr[tr[x].f].son[0]==x||tr[tr[x].f].son[1]==x))return false;
    return true;
}
int tmp[210000];
void splay(int x,int rt)
{
    int s=0,i=x;
    while(isroot(i)==false)
    {
        tmp[++s]=i;
        i=tr[i].f;
    } 
    tmp[++s]=i;
    while(s!=0)
    {
        i=tmp[s];s--;
        if(tr[i].fz==true)reverse(i);
    }
    
    while(isroot(x)==false)
    {
        int f=tr[x].f,ff=tr[f].f;
        if(isroot(f)==true)
        {
            if(x==tr[f].son[0])rotate(x,1);
            else rotate(x,0);
        }
        else
        {
                 if(tr[f].son[0]==x&&tr[ff].son[0]==f){rotate(f,1);rotate(x,1);}
            else if(tr[f].son[1]==x&&tr[ff].son[0]==f){rotate(x,0);rotate(x,1);}
            else if(tr[f].son[0]==x&&tr[ff].son[1]==f){rotate(x,1);rotate(x,0);}
            else if(tr[f].son[1]==x&&tr[ff].son[1]==f){rotate(f,0);rotate(x,0);}
        }
    }
}

//splay
 
void access(int x) 
{
    int y=0;
    while(x!=0)
    {
        splay(x,0);
        tr[x].son[1]=y;
        if(y!=0)tr[y].f=x;
        update(x);
        y=x;x=tr[x].f;
    }
}
void makeroot(int x)
{
    access(x);splay(x,0);
    tr[x].fz=1-tr[x].fz;
}
void Link(int x,int y)
{
    makeroot(x);tr[x].f=y;access(x);
}
void Cut(int x,int y)
{
    makeroot(x);
    access(y);splay(y,0);
    tr[tr[y].son[0]].f=0;tr[y].son[0]=0;
    update(y);
}
int findroot(int x)
{
    access(x);splay(x,0);
    while(tr[x].son[0]!=0)x=tr[x].son[0];
    return x;
}
 
//simple
 
int getdis(int x,int y)
{
    makeroot(x);
    access(y);splay(y,0);
    int ret=1;
    while(y!=x){y=tr[y].son[0];ret+=tr[tr[y].son[1]].c+1;}
    return ret;
}
 
 
//-------------------LCT------------------- 
 
 
bool intree[210000];//该边是否在树上 
int main()
{
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);
    
    int n,m,T;
    scanf("%d%d%d",&n,&m,&T);yu(n);
    int st,ed;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a[i].x,&a[i].y);
        scanf("%d%d",&st,&ed);st++;ed++;
        if(st>=ed){i--;m--;continue;}
        heap_st tt;
        tt.st=st, tt.ed=ed, tt.id=i;
        A.push(tt);
    }
     
    int tim=0;
    memset(intree,false,sizeof(intree));
    for(int t=1;t<=T;t++)
    {
        while(B.empty()==false)
        {
            heap_ed h=B.top();
            if(h.ed==t)
            {
                B.pop();
                int k=h.id;
                if(intree[k]==true)
                {
                    intree[k]=false;
                    Cut(a[k].x,a[k].y);
                }
            }
            else break;
        }
         
        //----------结束时间到,删除树上边,非树上边可以直接无视,更新-------
         
        while(A.empty()==false)
        {
            heap_st h=A.top();
            if(h.st==t)
            {
                A.pop();
                 
                heap_ed tt;
                tt.ed=h.ed, tt.id=h.id;
                B.push(tt);
                 
                heap_mt uu;
                uu.ed=h.ed, uu.id=h.id;
                C.push(uu);
            }
            else break;
        }
         
        //----------起始时间到,将边入堆---------- 
         
        while(C.empty()==false)
        {
            heap_mt h=C.top();C.pop();
            if(h.ed<=t)break;
            int k=h.id;
            int x=a[k].x,y=a[k].y;
            if(x==y){tim=max(tim,h.ed-1);continue;}
            if(findroot(x)!=findroot(y))
            {
                intree[k]=true;
                Link(x,y);
            }
            else
            {
                if(getdis(x,y)%2==1)
                    tim=max(tim,h.ed-1);
            }
        }
 
        //----------将树边连满&&判奇环---------------- 
         
        if(t<=tim)printf("No\n");
        else printf("Yes\n");
    }
    return 0;
}
lj的WAcode

 

--------------------然而cdq+带权并查集搞出来了。。。-----------------------

感觉这个不算cdq分治,只是普通分治而已-_-! upd:这个东西其实叫线段树分治。。。。。

具体怎么做呢,就是类似线段树一样把每一时间段下放影响,这样可以保证对于当前这一段包含的边都是没消失的,然后假如遇到奇环就把当前区间全部设为false就行。

 

dis可以直接用异或代替,因为只是要判奇偶性,路径不用压缩,修改需要父亲,分治可以保证平衡。

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;

int fa[210000],d[210000];
int findfa(int x)
{
    while(x!=fa[x])x=fa[x];
    return x;
}
int getdis(int x)
{
    int dis=0;
    while(x!=fa[x])dis^=d[x],x=fa[x];
    return dis;
}

//---------union-find sets------------- 

int top,sta[410000];bool v[410000];
int rak[210000];
void Link(int x,int y,int dis)
{
    if(rak[x]>rak[y])
    {
        top++;
        sta[top]=y,v[top]=true;
        fa[y]=x,d[y]=dis;
    }
    else if(rak[x]<rak[y])
    {
        top++;
        sta[top]=x,v[top]=true;
        fa[x]=y,d[x]=dis;
    }
    else
    {
        rak[x]++;top++;
        sta[top]=y,v[top]=false;
        fa[y]=x,d[y]=dis;
    }
}
void Cut(int now)
{
    while(now!=top)
    {
        int k=sta[top];top--;
        if(v[top+1]==false)rak[fa[k]]--;
        fa[k]=k, d[k]=0;
    }
}

//------------------玄学-------------------------------- 

struct edge{int x,y,st,ed;};
bool as[210000];
void cdq(int l,int r,vector<edge> hh)
{
    int mid=(l+r)/2;
    vector<edge> ll,rr;
    
    int len=hh.size(),now=top;
    for(int i=0;i<len;i++)
    {
        edge e=hh[i];
        if(e.st==l&&e.ed==r)
        {
            int x=e.x,y=e.y;
            int fx=findfa(x),fy=findfa(y);
            int dis=getdis(x)^getdis(y)^1;
            
            if(fx!=fy)Link(fx,fy,dis);
            else if((dis&1)>0)
            {
                for(int i=l;i<=r;i++)as[i]=false;
                Cut(now);
                return ;
            }
        }
        else if(e.ed<=mid)  ll.push_back(e);
        else if(mid+1<=e.st)rr.push_back(e);
        else
        {
            edge lc,rc;lc=rc=e;
            lc.ed=mid;rc.st=mid+1;
            ll.push_back(lc);
            rr.push_back(rc);
        }
    }
    
    if(l==r)as[l]=true;
    else cdq(l,mid,ll), cdq(mid+1,r,rr);
    Cut(now);
}

vector<edge> S;
int main()
{
 
    int n,m,T;
    scanf("%d%d%d",&n,&m,&T);
    for(int i=1;i<=m;i++)
    {
        int x,y,st,ed;
        scanf("%d%d%d%d",&x,&y,&st,&ed);
        if(st>=ed)continue;
        st++; S.push_back((edge){x,y,st,ed});
    }
    
    for(int i=1;i<=n;i++)fa[i]=i;
    memset(d,0,sizeof(d));
    memset(rak,0,sizeof(rak));
    top=0;
    
    cdq(1,T,S);
    
    for(int i=1;i<=T;i++)
        if(as[i]==true)printf("Yes\n");
        else printf("No\n");
    return 0;
}
现在已经看不懂的代码

 

-------------------------------再一次upd----------------------------------------

学会了线段树分治就是傻子题了,只要上并查集判奇环即可

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;

struct edge{int x,y;}e[210000];
struct node
{
    int l,r,lc,rc;
    vector<int>id,u;
}tr[210000];int trlen;
void bt(int l,int r)
{
    int now=++trlen;
    tr[now].l=l;tr[now].r=r;
    tr[now].lc=tr[now].rc=-1;
    if(l<r)
    {
        int mid=(l+r)/2;
        tr[now].lc=trlen+1;bt(l,mid);
        tr[now].rc=trlen+1;bt(mid+1,r);
    }
}
void insert(int now,int l,int r,int p)
{
    if(tr[now].l==l&&tr[now].r==r)
    {
        tr[now].id.push_back(p);
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(tr[now].l+tr[now].r)/2;
    
         if(r<=mid)  insert(lc,l,r,p);
    else if(mid+1<=l)insert(rc,l,r,p);
    else insert(lc,l,mid,p),insert(rc,mid+1,r,p);
}

//---------------------------------------init----------------------------------------------------

int fa[210000]; const int ot=101000;
int findfa(int x)
{
    if(fa[x]<0)return x;
    return findfa(fa[x]);
}
void merge(int now,bool &bk,int x,int y)
{
    int fx1=findfa(x),fy2=findfa(y+ot);
    if(fx1!=fy2)
    {
        if(fa[fx1]>fa[fy2])
        {
            tr[now].u.push_back(fx1);
            fa[fy2]+=fa[fx1];
            fa[fx1]=fy2;
        }
        else
        {
            tr[now].u.push_back(fy2);
            fa[fx1]+=fa[fy2];
            fa[fy2]=fx1;
        }
    }
    int fy1=findfa(y),fx2=findfa(x+ot);
    if(fx2!=fy1)
    {
        if(fa[fx2]>fa[fy1])
        {
            tr[now].u.push_back(fx2);
            fa[fy1]+=fa[fx2];
            fa[fx2]=fy1;
        }
        else
        {
            tr[now].u.push_back(fy1);
            fa[fx2]+=fa[fy1];
            fa[fy1]=fx2;
        }
    }
    
    if(findfa(fx1)==findfa(fx2)||findfa(fy1)==findfa(fy2))bk=false;
}
struct Answer{int l,r;bool b;}as[110000];int tp;
void dfs(int now)
{
    bool bk=true;
    for(int i=0;i<tr[now].id.size();i++)
        merge(now,bk,e[tr[now].id[i]].x,e[tr[now].id[i]].y);
    if(bk==false)
    {
        as[++tp].l=tr[now].l,as[tp].r=tr[now].r,as[tp].b=false;    
    }
    else
    {
        if(tr[now].l==tr[now].r)as[++tp].l=as[tp].r=tr[now].l,as[tp].b=true;
        else
        {
            dfs(tr[now].lc);
            dfs(tr[now].rc);
        }
    }
    
    for(int i=0;i<tr[now].u.size();i++)
        fa[tr[now].u[i]]=-1;
}

int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int n,m,T,st,ed;
    scanf("%d%d%d",&n,&m,&T);
    trlen=0;bt(1,T);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&e[i].x,&e[i].y,&st,&ed);
        if(st>=ed){i--,m--;continue;}
        insert(1,st+1,ed,i);
    }
    memset(fa,-1,sizeof(fa));
    tp=0;dfs(1);
    for(int i=1;i<=tp;i++)
        for(int j=as[i].l;j<=as[i].r;j++)
            if(as[i].b)printf("Yes\n");
            else printf("No\n");
    
    return 0;
}

 

pain and happy in the cruel world.
posted @ 2018-03-06 19:09  AKCqhzdy  阅读(156)  评论(0编辑  收藏  举报