【比赛】这次应该叫高二上一调(部分)
T2 回家
1 必经点一定是割点
2 割点不一定是必经点
3 n点到1点的路上经过的割点不一定是必经点
法1:
重新考虑割点定义
一个点是割点因为去掉它后图不联通
但不一定去掉它之后它的所有子树都不连通
我们认为当去掉它之后n点所在子树被分裂则该点是割点
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; } }
法2:
维护一个get
表示当n在v子树上且n不经过u-v树边能追溯到的dfn最小的点
(不经过树边u-v不等于不经过树边)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; } }
T3 寿司
考虑o(n)拆环 o(1) 计算
计算是问题转化成了:
平面上有n个点 选一个点到所有点距离最小
其实奇数个点偶数个点都一样 但是以防万一分开处理
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; } }