Loading

【比赛】这次应该叫高二上一调(部分)

T2 回家

 

1 必经点一定是割点

2 割点不一定是必经点

3 n点到1点的路上经过的割点不一定是必经点

法1:

重新考虑割点定义

一个点是割点因为去掉它后图不联通

但不一定去掉它之后它的所有子树都不连通

我们认为当去掉它之后n点所在子树被分裂则该点是割点

#include<bits/stdc++.h>
#define Sa Sakura 
#define Re register int
#define _ putchar(' ')
#define el putchar('\n')
#define maxn 1000010

using namespace std;

inline int read(){
    int f=0,x=0;char c=getchar();
    while(c<'0'||c>'9') f|=c=='-',c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return f?-x:x;
}

inline void ot(long long x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) ot(x/10);putchar(x%10|48);
}

int t,n,m;
int tot,head[maxn],nextt[maxn],ver[maxn];
int low[maxn],dfn[maxn],tim,fa[maxn];
int a[maxn],top;
bool flag[maxn],ju[maxn];

inline void empty(){
    tot=1;top=0;tim=0;
    for(Re i=1;i<=n;i++) low[i]=dfn[i]=head[i]=fa[i]=flag[i]=ju[i]=0;
    flag[n]=true;
}

inline void add(int x,int y){
    ver[++tot]=y;
    nextt[tot]=head[x];
    head[x]=tot;
}

void tarjan(int u,int ie){
    fa[u]=ver[ie^1];
    low[u]=dfn[u]=++tim;
    for(Re i=head[u];i;i=nextt[i])
        if(i!=(ie^1)){
            int v=ver[i];
            if(!dfn[v]){
                tarjan(v,i);
                low[u]=min(low[u],low[v]);
                flag[u]|=flag[v];
                if(dfn[u]<=low[v]&&flag[v]&&u!=1&&u!=n) ju[u]=true,top++;
            }else low[u]=min(low[u],dfn[v]);
        }
//    ot(u),_,ot(gett),_,ot(flag[u]),_,ot(low[u]),el;
}

main(){
    t=read();
    while(t--){
        n=read(),m=read();
        empty();
        for(Re i=1;i<=m;i++){
            int x=read(),y=read();
            add(x,y);
            add(y,x); 
        }
        tarjan(1,0);
    //    for(Re i=1;i<=n;i++) if(flag[i]) ot(i),_;el;
    //    for(Re i=1;i<=n;i++) if(cut[i]) ot(i),_;el;
        ot(top),el;
        for(Re i=1;i<=n;i++) if(ju[i]) ot(i),_;el;
    }
}
View Code

 法2:

维护一个get 

表示当n在v子树上且n不经过u-v树边能追溯到的dfn最小的点

(不经过树边u-v不等于不经过树边)

#include<bits/stdc++.h>
#define Sa Sakura 
#define Re register int
#define _ putchar(' ')
#define el putchar('\n')
#define maxn 1000010

using namespace std;

inline int read(){
    int f=0,x=0;char c=getchar();
    while(c<'0'||c>'9') f|=c=='-',c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return f?-x:x;
}

inline void ot(long long x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) ot(x/10);putchar(x%10|48);
}

int t,n,m;
int tot,head[maxn],nextt[maxn],ver[maxn];
int low[maxn],dfn[maxn],tim,fa[maxn];
int a[maxn],top;
bool flag[maxn],ju[maxn];

inline void empty(){
    tot=1;top=0;tim=0;
    for(Re i=1;i<=n;i++) low[i]=dfn[i]=head[i]=fa[i]=flag[i]=ju[i]=0;
    flag[n]=true;
}

inline void add(int x,int y){
    ver[++tot]=y;
    nextt[tot]=head[x];
    head[x]=tot;
}

void tarjan(int u,int ie){
    fa[u]=ver[ie^1];
    low[u]=dfn[u]=++tim;
    for(Re i=head[u];i;i=nextt[i])
        if(i!=(ie^1)){
            int v=ver[i];
            if(!dfn[v]){
                tarjan(v,i);
                low[u]=min(low[u],low[v]);
                flag[u]|=flag[v];
                if(dfn[u]<=low[v]&&flag[v]&&u!=1&&u!=n) ju[u]=true,top++;
            }else low[u]=min(low[u],dfn[v]);
        }
//    ot(u),_,ot(gett),_,ot(flag[u]),_,ot(low[u]),el;
}

main(){
    t=read();
    while(t--){
        n=read(),m=read();
        empty();
        for(Re i=1;i<=m;i++){
            int x=read(),y=read();
            add(x,y);
            add(y,x); 
        }
        tarjan(1,0);
    //    for(Re i=1;i<=n;i++) if(flag[i]) ot(i),_;el;
    //    for(Re i=1;i<=n;i++) if(cut[i]) ot(i),_;el;
        ot(top),el;
        for(Re i=1;i<=n;i++) if(ju[i]) ot(i),_;el;
    }
}
View Code

 

T3 寿司

考虑o(n)拆环 o(1) 计算

计算是问题转化成了:

平面上有n个点 选一个点到所有点距离最小

其实奇数个点偶数个点都一样 但是以防万一分开处理

#include<bits/stdc++.h>
#define Sa Sakura 
#define Re register int
#define _ putchar(' ')
#define el putchar('\n')
#define maxn 1000010
#define int long long

using namespace std;

inline int read(){
    int f=0,x=0;char c=getchar();
    while(c<'0'||c>'9') f|=c=='-',c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return f?-x:x;
}

inline void ot(long long x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) ot(x/10);putchar(x%10|48);
}

int t,n,m,ans;
int q[maxn*2],l,r;
char s[maxn];

inline void odd(){
    int sum1=0,sum2=0;
    ans=n*n;
    for(Re i=1;i<=m/2;i++) sum1+=q[i];
    for(Re i=(m+1)/2+1;i<=m;i++) sum2+=q[i];
    for(Re i=1;i<=m;i++){
    //    _;for(Re j=l;j<=r;j++) ot(q[j]),_;el;
        int mid=l+r>>1;
        int x=q[mid]*(m/2)-(m/2+1)*(m/2)/2;
        int y=q[mid]*(m/2)+(m/2+1)*(m/2)/2;
    //    ot(mid),_,ot(q[mid]),_,ot(x),_,ot(y),_,ot(sum1),_,ot(sum2),el;
        ans=min(ans,x-sum1+sum2-y);
        sum1+=q[mid]-q[l];
        sum2+=q[l]+n-q[mid+1]; 
        q[++r]=q[l++]+n;
    }
}

inline void even(){
    int sum1=0,sum2=0;
    ans=n*n;
    for(Re i=1;i<=m/2;i++) sum1+=q[i];
    for(Re i=m/2+1;i<=m;i++) sum2+=q[i];
    for(Re i=1;i<=m;i++){
    //    _;for(Re j=l;j<=r;j++) ot(q[j]),_;el;
        int mid=l+r>>1;
        int x=q[mid]*(m/2)-(m/2-1)*(m/2)/2;
        int y=q[mid+1]*(m/2)+(m/2-1)*(m/2)/2;
    //    ot(mid),_,ot(q[mid]),_,ot(x),_,ot(y),_,ot(sum1),_,ot(sum2),el;
        ans=min(ans,x-sum1+sum2-y+(q[mid+1]-q[mid]-1)*(m/2));
        sum1+=q[mid+1]-q[l];
        sum2+=q[l]+n-q[mid+1]; 
        q[++r]=q[l++]+n;
        
    }
}

main(){
    t=read();
    while(t--){
        scanf(" %s",s+1);
        n=strlen(s+1);
        l=1;r=0;
        for(Re i=1;i<=n;i++) if(s[i]=='B') q[++r]=i;
    //    for(Re i=1;i<=r;i++) ot(q[i]),_;el;
        m=r;
        if(r<=1||r>=n-1){
            ot(0),el;
            continue;
        }
        if(r&1) odd();
        else even();
        ot(ans),el;
    }
}
View Code

 

posted @ 2022-07-13 20:36  hzoi_Sakura  阅读(20)  评论(0编辑  收藏  举报