[bzoj4025]二分图 解题报告

11 篇文章 0 订阅
3 篇文章 0 订阅

最近在学lct,拿这道题学了动态图。
法一:
很神的分块(用vector常数太大t了。。)
按时间分块,先将覆盖整个块的边缩起来,然后枚举每一个时间对于块内的边暴力;缩点和暴力都是O(边数目)的。这样的话每个边都会被扫 O(n) 遍,时间复杂度 O(nn)6.5107 ,然后加上我用了vector,常数巨大。。
法二:
很傻b的ufs。
用类似线段树打标记的方法dfs,记下来每次修改了数组中的哪些,每次回溯的时候暴力修改。时间复杂度 O(nlog2n) ,由于我用了vector,常数巨大。。
法三:
很神的lct。
考虑按照时间从前向后扫描,对于一个环,显然在环中第一个被删的边被删之前,这个环的奇偶性是不会改变的。所以我们选择将这条边从树中提出来,因为它所产生的影响已经确定了。
直观上来看就是在维护删除时间的最大生成树。时间复杂度 O(nlogn)
分块(TLE了):

#include<cstdio>
#include<iostream>
using namespace std;
#include<algorithm>
#include<cmath>
#include<cstring>
void in(int &x){
    char c=getchar();
    while(c<'0'||c>'9')c=getchar();
    for(x=0;c>='0'&&c<='9';c=getchar())x=x*10+(c^'0');
}
#include<vector>
const int S=316;
//const int S=2;
struct BS{
    vector< pair<int,int> > ae[320],be;
}b[320];
int fa[100005],color[100005];
int p[2];
int ptr[100005],next[200005],succ[200005],etot=1;
void addedge(int from,int to){
    //printf("Addedge(%d->%d)\n",from,to);
    next[etot]=ptr[from],ptr[from]=etot,succ[etot++]=to;
}
bool bdfs(int node,int nc){
    if(fa[node])
        if(fa[node]==p[nc])return 1;
        else return 0;
    else fa[node]=p[nc];
    for(int i=ptr[node];i;i=next[i])
        if(!bdfs(succ[i],!nc))
            return 0;
    return 1;
}
bool adfs(int node,int nc){
    if(~color[node])
        if(color[node]==nc)return 1;
        else return 0;
    else color[node]=nc;
    for(int i=ptr[node];i;i=next[i])
        if(!adfs(succ[i],!nc))
            return 0;
    return 1;
}
int main(){
    freopen("bzoj_4025.in","r",stdin);
    //freopen("bzoj_4025_block.out","w",stdout);
    int n,m,T,i,j,u,v,start,end;
    int tot=0;
    in(n),in(m),in(T);
    while(m--){
        in(u),in(v),in(start),in(end);
        ++start;
        //printf("--[%d,%d]--\n",start,end);
        if(start/S<end/S){
            for(i=start;i/S==start/S;++i){
                b[i/S].ae[i%S].push_back(make_pair(u,v));
                ++tot;
            }
            for(i=end;i/S==end/S;--i){
                b[i/S].ae[i%S].push_back(make_pair(u,v));
                ++tot;
            }
            for(i=start/S;++i<end/S;){
                b[i].be.push_back(make_pair(u,v));
                ++tot;
            }
        }
        else
            for(i=start;i<=end;++i){
                b[i/S].ae[i%S].push_back(make_pair(u,v));
                ++tot;
            }
    }
    printf("%d\n",tot);
    return 0;
    int k,t0,t1;
    bool ans;
    for(i=1;i<=T;++i){
        if(i==1||i%S==0){
            t0=i/S;

            //printf("---block(%d)---\n",t0);
            //for(j=b[t0].be.size();j--;)printf("(%d,%d)\n",b[t0].be[j].first,b[t0].be[j].second);

            ans=1;
            memset(fa,0,sizeof(fa));
            for(j=b[t0].be.size();j--;){
                addedge(b[t0].be[j].first,b[t0].be[j].second),addedge(b[t0].be[j].second,b[t0].be[j].first);
                if(b[t0].be[j].first==b[t0].be[j].second){
                    ans=0;
                    break;
                }
            }
            if(ans){
                for(j=b[t0].be.size();j--;)
                    if(!fa[b[t0].be[j].first]){
                        p[0]=b[t0].be[j].first,p[1]=b[t0].be[j].second;
                        if(!bdfs(b[t0].be[j].first,0)){
                            ans=0;
                            break;
                        }
                    }
                for(j=n;j;--j)
                    if(!fa[j])
                        fa[j]=j;
            }
            etot=1;
            memset(ptr,0,sizeof(ptr));

            //printf("blockans=%d\n",ans);
        }
        if(ans){
            t1=i%S;

            //printf("---%d:(%d,%d)---\n",i,t0,t1);
            //for(j=b[t0].ae[t1].size();j--;)printf("(%d,%d)\n",b[t0].ae[t1][j].first,b[t0].ae[t1][j].second);

            for(j=b[t0].ae[t1].size();j--;){
                addedge(fa[b[t0].ae[t1][j].first],fa[b[t0].ae[t1][j].second]),addedge(fa[b[t0].ae[t1][j].second],fa[b[t0].ae[t1][j].first]);
                color[fa[b[t0].ae[t1][j].first]]=color[fa[b[t0].ae[t1][j].second]]=-1;
            }
            for(j=b[t0].ae[t1].size();j--;)
                if(color[fa[b[t0].ae[t1][j].first]]==-1&&!adfs(fa[b[t0].ae[t1][j].first],0))
                    break;
            if(~j)puts("No");
            else puts("Yes");
            etot=1;
            for(j=b[t0].ae[t1].size();j--;)ptr[fa[b[t0].ae[t1][j].first]]=ptr[fa[b[t0].ae[t1][j].second]]=0;
        }
        else puts("No");
    }
}

ufs(常数巨大):

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
const int Z=1<<17;
void in(int &x){
    char c=getchar();
    while(c<'0'||c>'9')c=getchar();
    for(x=0;c>='0'&&c<='9';c=getchar())x=x*10+(c^'0');
}
//(node<<1)-1是它自己,node<<1是它的敌人。 
vector< pair<int,int> > e[Z<<1];
int fa[200005],sz[200005];
vector< pair<int,int> > flist[Z<<1],slist[Z<<1];
void link(int node,int x,int y){//x->y
    flist[node].push_back(make_pair(x,fa[x]));
    fa[x]=y;
}
int find(int node,int x){
    int root=fa[x],ftr=fa[x];
    while(root!=fa[root])root=fa[root];
    for(;ftr!=root;x=ftr,ftr=fa[ftr])link(node,x,root);
    return root;
}
void merge(int node,int x,int y){
    //printf("Merge(%d,%d)\n",x,y);
    if(x==y)return;
    if(sz[x]>sz[y])swap(x,y);
    slist[node].push_back(make_pair(y,sz[y]));
    sz[y]+=sz[x];
    link(node,x,y);
}
int T;

int l[Z<<1],r[Z<<1];

void dfs(int node,bool ans){
    //printf("---[%d,%d] %d---\n",l[node],r[node],ans);
    bool now=ans;
    int i;
    if(ans){
        for(i=e[node].size();i--;){
            //printf("Addedge(%d,%d)\n",e[node][i].first,e[node][i].second);
            if(find(node,e[node][i].first<<1)==find(node,e[node][i].second<<1)){
                //printf("Maodun:fa[%d]=%d,fa[%d]=%d\n",e[node][i].first<<1,fa[e[node][i].first<<1],e[node][i].second<<1,fa[e[node][i].second<<1]);
                now=0;
                break;
            }
            else{
                //puts("Fuhe");
                //printf("%d %d\n",fa[e[node][i].first<<1],fa[e[node][i].second<<1]);
                merge(node,fa[e[node][i].first<<1],find(node,(e[node][i].second<<1)-1));
                merge(node,find(node,(e[node][i].first<<1)-1),fa[e[node][i].second<<1]);
            }
        }
    }
    if(node<Z)dfs(node<<1,now),dfs(node<<1|1,now);
    else
        if(now)puts("Yes");
        else puts("No");
    if(ans){
        for(i=flist[node].size();i--;)fa[flist[node][i].first]=flist[node][i].second;
        for(i=slist[node].size();i--;)sz[slist[node][i].first]=slist[node][i].second;
    }
    //cout<<fa[2]<<endl;
}
int main(){
    freopen("bzoj_4025.in","r",stdin);
    freopen("bzoj_4025.out","w",stdout);
    int n,m,u,v,start,end;
    in(n),in(m),in(T);

    for(int i=T;i;--i)l[Z+i]=r[Z+i]=i;
    for(int i=Z;--i;){
        l[i]=l[i<<1]?l[i<<1]:l[i<<1|1];
        r[i]=r[i<<1|1]?r[i<<1|1]:r[i<<1];
    }

    while(m--){
        in(u),in(v),in(start),in(end);
        for(start+=Z,end+=Z+1;end-start>1;start>>=1,end>>=1){
            if(~start&1)e[start^1].push_back(make_pair(u,v));
            if(end&1) e[end^1].push_back(make_pair(u,v));
        }
    }
    for(int i=n<<1;i;--i){
        fa[i]=i;
        sz[i]=1;
    }
    int x=0;
    for(start=Z,end=Z+T+1;end-start>1;++x,start>>=1,end>>=1)
        if(~start&1)
            dfs(start^1,1);
    end=Z+T+1;
    while(x--){
        if(end>>x&1)
            dfs(end>>x^1,1);
        //cout<<"["<<l[end]<<","<<r[end]<<"]\n";
    }
}

lct:

#include<cstdio>
#include<iostream>
using namespace std;
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
void in(int &x){
    char c=getchar();
    while(c<'0'||c>'9')c=getchar();
    for(x=0;c>='0'&&c<='9';c=getchar())x=x*10+(c^'0');
}
struct LS{
    int ch[2],fa;
    int sz,wt,min,end;
    bool swapflag;
}lct[300005];
void update(int node){
    lct[node].sz=lct[lct[node].ch[0]].sz+lct[lct[node].ch[1]].sz+lct[node].wt;
    lct[node].min=min(lct[node].end,min(lct[lct[node].ch[0]].min,lct[lct[node].ch[1]].min));
}
void swappaint(int node){
    if(node){
        swap(lct[node].ch[0],lct[node].ch[1]);
        lct[node].swapflag^=1;
    }
}
void pushdown(int node){
    if(lct[node].swapflag){
        swappaint(lct[node].ch[0]),swappaint(lct[node].ch[1]);
        lct[node].swapflag^=1;
    }
}
void out(int node){
    printf("%d:ch[0]=%d,ch[1]=%d,fa=%d,sz=%d,wt=%d,min=%d,end=%d\n",node,lct[node].ch[0],lct[node].ch[1],lct[node].fa,lct[node].sz,lct[node].wt,lct[node].min,lct[node].end);
}
void outdfs(int node){
    out(node);
    pushdown(node);
    if(lct[node].ch[0])outdfs(lct[node].ch[0]);
    if(lct[node].ch[1])outdfs(lct[node].ch[1]);
}
bool is_top(int node){
    return lct[node].fa==0||lct[lct[node].fa].ch[1]!=node&&lct[lct[node].fa].ch[0]!=node;
}
void down(int node){
    if(!is_top(node))down(lct[node].fa);
    pushdown(node);
}
void rot(int node){
    int fa=lct[node].fa;
    bool dir=lct[fa].ch[1]==node;

    lct[node].fa=lct[fa].fa;
    lct[fa].fa=node;
    lct[lct[node].ch[!dir]].fa=fa;

    lct[fa].ch[dir]=lct[node].ch[!dir];
    lct[node].ch[!dir]=fa;
    if(lct[lct[node].fa].ch[1]==fa)lct[lct[node].fa].ch[1]=node;
    else if(lct[lct[node].fa].ch[0]==fa)lct[lct[node].fa].ch[0]=node;

    update(fa);
}
void splay(int node){
    down(node);
    for(int fa;!is_top(node);rot(node)){
        fa=lct[node].fa;
        if(!is_top(fa))
            if((lct[lct[fa].fa].ch[1]==fa)==(lct[fa].ch[1]==node))rot(fa);
            else rot(node);
    }
    update(node);
}
void discon(int node){
    splay(node);
    lct[node].ch[1]=0;
}
void access(int node){
    //printf("access(%d)\n",node);
    for(discon(node);lct[node].fa;rot(node)){
        discon(lct[node].fa);
        lct[lct[node].fa].ch[1]=node;
    }
    update(node);
    //outdfs(node);
    //puts("");
}
void makeroot(int node){
    access(node);
    swappaint(node);
}
void cut(int node){
    splay(node);
    lct[lct[node].ch[0]].fa=lct[node].fa,lct[lct[node].ch[1]].fa=0;
    lct[node].ch[0]=lct[node].ch[1]=0;
    //out(node);
}
void findmin(int node){
    while(lct[node].min!=lct[node].end){
        pushdown(node);
        if(lct[lct[node].ch[0]].min==lct[node].min)node=lct[node].ch[0];
        else node=lct[node].ch[1];
    }
    cut(node);
}
void getchain(int u,int v){
    makeroot(u);
    access(v);
}
void link(int from,int to){
    makeroot(from);
    lct[from].fa=to;
}

struct ES{
    int u,v,start,end;
}e[200005];
bool cmp(const int &a,const int &b){
    return e[a].end<e[b].end;
}
vector<int> l[100005],r[100005];
int delta[100005];
int main(){
    freopen("bzoj_4025.in","r",stdin);
    freopen("bzoj_4025_lct.out","w",stdout);
    int n,m,T,i;
    in(n),in(m),in(T);
    for(i=m;i;--i){
        in(e[i].u),in(e[i].v),in(e[i].start),in(e[i].end);
        if(++e[i].start<=e[i].end)l[e[i].start].push_back(i),r[e[i].end].push_back(i);
    }
    for(i=n;~i;--i)lct[i].min=lct[i].end=0x7fffffff;
    for(i=m;i;--i){
        lct[n+i].wt=lct[n+i].sz=1;
        lct[n+i].min=lct[n+i].end=e[i].end;
    }
    int j,now=0;
    for(i=1;i<=T;++i){
        //printf("-------T:%d-------\n",i);
        //link
        sort(l[i].begin(),l[i].end());
        for(j=l[i].size();j--;){
            //printf("Add(%d)=(%d,%d,%d,%d)\n",n+l[i][j],e[l[i][j]].u,e[l[i][j]].v,e[l[i][j]].start,e[l[i][j]].end);
            if(e[l[i][j]].u!=e[l[i][j]].v){
                getchain(e[l[i][j]].u,e[l[i][j]].v);
                if(is_top(e[l[i][j]].u)){
                    link(e[l[i][j]].u,n+l[i][j]);
                    link(n+l[i][j],e[l[i][j]].v);
                    access(e[l[i][j]].u);
                }
                else{
                    if(~lct[e[l[i][j]].v].sz&1){
                        ++now;
                        //printf("%d %d(%d)\n",lct[e[l[i][j]].v].min,e[l[i][j]].end,l[i][j]);
                        --delta[min(lct[e[l[i][j]].v].min,e[l[i][j]].end)+1];
                        //cout<<lct[e[l[i][j]].v].min<<","<<e[l[i][j]].end<<endl;
                        //cout<<min(lct[e[l[i][j]].v].min,e[l[i][j]].end)+1<<endl;
                        //puts("Ji huan!");
                    }
                    if(lct[e[l[i][j]].v].min<e[l[i][j]].end){
                        findmin(e[l[i][j]].v);
                        link(e[l[i][j]].u,n+l[i][j]);
                        link(n+l[i][j],e[l[i][j]].v);
                        access(e[l[i][j]].u);
                    }
                }
            }
            else{
                ++now;
                --delta[e[l[i][j]].end+1];
            }
        }
        //query
        now+=delta[i];
        //cout<<delta[i]<<"->"<<now<<endl;
        if(now)puts("No");
        else puts("Yes");
        //cut
        for(j=r[i].size();j--;){
            //printf("Del(%d)=(%d,%d,%d,%d)\n",n+r[i][j],e[r[i][j]].u,e[r[i][j]].v,e[r[i][j]].start,e[r[i][j]].end);
            cut(n+r[i][j]);
        }
    }
}

总结:
①做数据结构题时,务必首先考虑分块。
②考虑无序的问题时,往往需要将其有序化。比如说将环中的边按删除时间考虑。
③cut一个点时,注意如果它不在root所在的splay中,就需要将它左儿子的父指针指向它的父亲。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: bzoj作为一个计算机竞赛的在线评测系统,不仅可以提供大量的题目供程序员练习和学习,还可以帮助程序员提升算法和编程能力。为了更好地利用bzoj进行题目的学习和刷题,制定一个bzoj做题计划是非常有必要的。 首先,我们需要合理安排时间,每天留出一定的时间来做bzoj的题目。可以根据自己的时间安排,每天挑选适量的题目进行解答。可以先从难度较低的题目开始,逐渐提高难度,这样既能巩固基础知识,又能挑战自己的思维能力。 其次,要有一个计划和目标。可以规划一个每周或每月的题目数量目标,以及每个阶段要学习和掌握的算法知识点。可以根据bzoj的题目分类,如动态规划、图论、贪心算法等,结合自己的实际情况,有针对性地选择题目进行学习。 此外,要充分利用bzoj提供的资源。bzoj网站上有很多高质量的题解和优秀的解题代码,可以参考和学习。还有相关的讨论区,可以与其他程序员交流和讨论,共同进步。 最后,要坚持并保持思考。做题不是单纯为了刷数量,更重要的是学会思考和总结。遇到难题时,要有耐心,多思考,多尝试不同的解法。即使不能一次性解出来,也要学会思考和分析解题过程,以及可能出现的错误和优化。 总之,bzoj做题计划的关键在于合理安排时间、制定目标、利用资源、坚持思考。通过有计划的刷题,可以提高算法和编程能力,并培养解决问题的思维习惯,在计算机竞赛中取得更好的成绩。 ### 回答2: bzoj做题计划是指在bzoj这个在线测评系统上制定一套学习和刷题的计划,并且将计划记录在excel表格中。该计划主要包括以下几个方面的内容。 首先是学习目标的设定。通过分析自己的水平和知识缺口,可以设定一个合理的目标,比如每天解决一定数量的题目或者提高特定的算法掌握程度。 其次是题目选择的策略。在excel表格中可以记录下自己选择的题目编号、题目类型和难度等信息。可以根据题目的类型和难度来安排每天的刷题计划,确保自己可以逐步提高技巧和解题能力。 然后是学习进度的记录和管理。将每天的完成情况记录在excel表格中,可以清晰地看到自己的学习进度和任务完成情况。可以使用图表等功能来对学习进度进行可视化展示,更好地管理自己的学习计划。 同时,可以在excel表格的备注栏中记录下每道题目的解题思路、关键点和需要复习的知识点等信息。这样可以方便自己回顾和总结,巩固所学的知识。 最后,可以将excel表格与其他相关资料进行整合,比如算法教材、题目解析和学习笔记等。这样可以形成一个完整的学习档案,方便自己进行系统的学习和复习。 总之,bzoj做题计划excel的制定和记录可以帮助我们更加有条理和高效地进行学习和刷题。通过合理安排学习目标和题目选择策略,记录学习进度和思路,并整合其他学习资料,我们可以提高自己的解题能力,并在bzoj上取得更好的成绩。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值