专项测试(图论1)

专项测试(图论1)

第一题是分块,没有想到,第二题暴力,没有对拍,第三题网络流,我人傻了

越来越难哈,到现在了啥也不会,啥也不是。

关于我网络流学了像没学一样,所以我打算多做一点网络流的题。。

T1 序列

直接分块维护,不会线段树

每个块维护一个偏移量,最小值,变化次数的差分数组

每次加的时候直接加就行,取最大值的是候\(lower_bound\)一下

分块有一个小问题,注意最右边的一块,循环的时候别忘了卡个边界

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*t;
}
const int N=2e5+5;
int n,m;
int mn[N],cf[N],ad[N],zc[N];
struct node{
    int v,id,ci;
    bool operator < (node a)const{
        return v<a.v;
    }
}a[N];
int bl[N],sq;
void dow(int x){
    fo(i,(x-1)*sq+2,x*sq)cf[i]+=cf[i-1];
    fo(i,(x-1)*sq+1,x*sq)a[i].ci+=cf[i]+zc[x],cf[i]=0;
    fo(i,(x-1)*sq+1,x*sq)a[i].v=a[i].v+ad[x]>mn[x]?a[i].v+ad[x]:mn[x];
    ad[x]=zc[x]=0;
}
void add(int x,int y,int z){
    if(!z)return ;
    dow(bl[x]);
    fo(i,(bl[x]-1)*sq+1,bl[x]*sq)if(a[i].id>=x&&a[i].id<=y)a[i].v+=z,a[i].ci++;
    sort(a+(bl[x]-1)*sq+1,a+bl[x]*sq+1);mn[bl[x]]=a[(bl[x]-1)*sq+1].v;
    fo(i,bl[x]+1,bl[y]-1)ad[i]+=z,zc[i]++,mn[i]+=z;
    if(bl[x]!=bl[y]){
        dow(bl[y]);
        fo(i,(bl[y]-1)*sq+1,bl[y]*sq)if(a[i].id>=x&&a[i].id<=y)a[i].v+=z,a[i].ci++;
        sort(a+(bl[y]-1)*sq+1,a+bl[y]*sq+1);mn[bl[y]]=a[(bl[y]-1)*sq+1].v;
    }
}
void pmx(int x,int y,int z){
    dow(bl[x]);
    fo(i,(bl[x]-1)*sq+1,bl[x]*sq)if(a[i].id>=x&&a[i].id<=y&&a[i].v<z)a[i].v=z,a[i].ci++;
    sort(a+(bl[x]-1)*sq+1,a+bl[x]*sq+1);mn[bl[x]]=a[(bl[x]-1)*sq+1].v;
    fo(i,bl[x]+1,bl[y]-1){
        if(mn[i]>=z)continue;
        mn[i]=z;int pos=lower_bound(a+(i-1)*sq+1,a+i*sq+1,node{z-ad[i],0})-a;
        cf[(i-1)*sq+1]++;if(pos<=i*sq)cf[pos]--;
    }
    if(bl[x]!=bl[y]){
        dow(bl[y]);
        fo(i,(bl[y]-1)*sq+1,bl[y]*sq)if(a[i].id>=x&&a[i].id<=y&&a[i].v<z)a[i].v=z,a[i].ci++;
        sort(a+(bl[y]-1)*sq+1,a+bl[y]*sq+1);mn[bl[y]]=a[(bl[y]-1)*sq+1].v;
    }
}
void query(int x){
    dow(bl[x]);
    fo(i,(bl[x]-1)*sq+1,bl[x]*sq)if(a[i].id==x)printf("%lld %lld\n",a[i].v,a[i].ci);
}
signed main(){
    n=read();sq=sqrt(n);
    fo(i,1,n)a[i].v=read(),a[i].id=i;
    fo(i,1,n)bl[i]=(i-1)/sq+1;
    fo(i,1,(n-1)/sq+1){
        sort(a+(i-1)*sq+1,a+i*sq+1);
        mn[i]=a[(i-1)*sq+1].v;
    }
    m=read();
    while(m--){
        char tp[5];scanf("%s",tp+1);
        int x=read(),y,z;
        if(tp[1]=='A'){
            y=read();z=read();
            add(x,y,z);
        }
        if(tp[1]=='M'){
            y=read();z=read();
            pmx(x,y,z);
        }
        if(tp[1]=='Q')query(x);
    }
}

T2 旅行计划

奇数的时候全是\(0\),因为可以在某一条路径上走\(K\)

偶数的时候发现之和路径的奇偶性有关,于是就切了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*t;
}
const int N=1e5+5;
int n,m,q;
int to[N*2],nxt[N*2],val[N*2],head[N],rp;
void add_edg(int x,int y,int z){
    to[++rp]=y;val[rp]=z;
    nxt[rp]=head[x];head[x]=rp;
}
int fai[N],gd[N];
int find(int x){return fai[x]==x?x:fai[x]=find(fai[x]);}
int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
int dis[N][2];
void dfs(int x,int t,int g){
    if(dis[x][t])return ;dis[x][t]=1;
    for(int i=head[x];i;i=nxt[i])dfs(to[i],t^((val[i]/g)&1),g);
}
signed main(){
    n=read();m=read();q=read();
    fo(i,1,n)fai[i]=i;
    fo(i,1,m){
        int u=read(),v=read(),w=read();
        add_edg(u,v,w);add_edg(v,u,w);
        int fx=find(u),fy=find(v);
        if(fx!=fy)fai[fx]=fy,gd[fy]=gcd(gd[fy],gd[fx]);
        gd[fy]=gcd(gd[fy],w);
    }
    fo(i,1,n)if(fai[i]==i)dfs(i,0,gd[i]);
    fo(i,1,q){
        int x=read(),y=read(),k=read();
        if(find(x)!=find(y)){printf("NIE\n");continue;}
        bool fl=false;int nw=k,mw=gd[find(x)]*2,gu=gcd(gd[find(x)]*2,k);
        while(!(nw&1)){
            nw>>=1;mw>>=1;
            if(mw&1){fl=true;break;}
        }
        // cerr<<nw<<" "<<mw<<" "<<fl<<endl;
        if(!fl){printf("0\n");continue;}
        // cerr<<"gu"<<" "<<gu<<endl;
        fl=((dis[x][1]&&dis[y][1])||(dis[x][0]&&dis[y][0]));
        if(!fl)printf("%lld\n",gu/2);
        else printf("0\n");
    }
    return 0;
}

T3 Hack

确实是一眼就知道是最小割,但是不知道咋建图

于是题解告诉我要把反边全部建成\(inf\)

仔细理解了一下,发现这样建图的话,横叉边是可以不断退流的

所以一个横叉边链接的路径必须在同一侧割掉,于是我们就完美的避免了统一路径上有两个割边的情况

由于每个边都有可能作为横叉边,所以我们就干脆都把反边设成\(inf\)

于是乎,\(WA\)\(70pts\),怎么回事??发现如果有一个点向\(s\)有连边,\(t\)向它有连边,那么你就完蛋了,因为你必须要把\(inf\)割掉

于是我们要预先判断一个点是否能被\(s\)到达,并且是否可以到达\(t\)

哦对了,还有如果\(1\)\(n\)在一个强连通分量里,那是不行的,无解

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*t;
}
const int inf=0x3f3f3f3f3f3f3f3f;
const int N=105;
const int M=2505;
int n,m,s,t;
struct D{int x,y,v;}d[M];
struct E{int to,nxt,val;}e[M*2];
int head[N],hea[N],rp;
void add_edg(int x,int y,int w){
    e[++rp].to=y;e[rp].val=w;
    e[rp].nxt=head[x];head[x]=rp;
}
int dfn[N],low[N],cnt;
int bl[N],col,sta[N],top;
void tarjan(int x){
    low[x]=dfn[x]=++cnt;
    sta[++top]=x;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(!dfn[y])tarjan(y),low[x]=min(low[x],low[y]);
        else if(!bl[y])low[x]=min(low[x],dfn[y]);
    }
    if(dfn[x]==low[x]){
        bl[x]=++col;
        while(sta[top]!=x)bl[sta[top]]=col,top--;
        top--;
    }
}
int dis[N];
bool bfs(){
    memset(dis,0x3f,sizeof(dis));
    memcpy(head,hea,sizeof(hea));
    queue<int> q;while(!q.empty())q.pop();
    q.push(s);dis[s]=0;
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=head[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(!e[i].val||dis[y]<=dis[x]+1)continue;
            dis[y]=dis[x]+1;q.push(y);
            if(y==t)return true;
        }
    }
    return false;
}
int dfs(int x,int in){
    if(x==t)return in;
    int rest=in,go=0;
    for(int i=head[x];i;head[x]=i=e[i].nxt){
        int y=e[i].to;
        if(!e[i].val||dis[y]!=dis[x]+1)continue;
        go=dfs(y,min(rest,e[i].val));
        if(go)e[i].val-=go,e[i^1].val+=go,rest-=go;
        else dis[y]=0;
        if(!rest)break;
    }
    return in-rest;
}
int dinic(){
    int ret=0;
    memcpy(hea,head,sizeof(head));
    while(bfs())ret+=dfs(s,inf);
    return ret;
}
bool vis[N],via[N];
bool pd(int x){
    if(x==bl[n])return true;
    if(via[x])return vis[x];
    via[x]=true;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;
        vis[x]|=pd(y);
    }
    return vis[x];
}
signed main(){
    n=read();m=read();s=1;t=n;
    fo(i,1,m){
        d[i].x=read()+1;d[i].y=read()+1;d[i].v=read();
        add_edg(d[i].x,d[i].y,0);
    }
    fo(i,1,n)if(!dfn[i])tarjan(i);
    memset(head,0,sizeof(head));rp=1;
    fo(i,1,m){
        if(bl[d[i].x]==bl[d[i].y])continue;
        add_edg(bl[d[i].x],bl[d[i].y],0);
    }
    pd(bl[1]);vis[bl[1]]=vis[bl[n]]=true;
    if(bl[1]==bl[n]){printf("-1");return 0;}
    memset(head,0,sizeof(head));rp=1;
    fo(i,1,m){
        if(!vis[bl[d[i].x]]||!vis[bl[d[i].y]])continue;
        add_edg(d[i].x,d[i].y,d[i].v);
        add_edg(d[i].y,d[i].x,inf);
    }
    printf("%lld",dinic());
}
posted @ 2021-12-23 15:32  fengwu2005  阅读(50)  评论(0编辑  收藏  举报