191005CSP模拟题解

T1:对于每条边,求删了这条边原图能否成为二分图,点边规模2e6
解法:首先判掉无奇环和一个奇环的情况
一条边合法当且仅当其属于所有奇环的交集且不属于任何一个偶环(会构成新的奇环)
那就弄个dfs树,对于每条返祖边树上差分一下,奇环+1偶环-1,最后看差分值是否为奇环个数即可

Code:

#include
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=2e6+5;
int vis[N<<1],head[N<<1],nxt[N<<1],tot=1;
inline void add(int x,int y){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
int dep[N],pt[N],f[N],cnt,tmp;
void dfs(int v,int fa){
	pt[v]=1;
	for(int i=head[v];i;i=nxt[i]){
		if(i==(fa^1)) continue;
		int y=vis[i];
		if(!pt[y]) dep[y]=dep[v]+1,dfs(y,i),f[v]+=f[y];
		else{
			if(dep[y]>dep[v]) continue;
			if((dep[v]-dep[y]+1)&1) ++f[v],--f[y],++cnt,tmp=i>>1;
			else --f[v],++f[y];
		}
	}
}
int ans[N],cntans=0;
inline void dfs2(int v,int fa){
	pt[v]=1;
	if(f[v]==cnt) ans[++cntans]=fa>>1;
	for(int i=head[v];i;i=nxt[i]) if(!pt[vis[i]]) dfs2(vis[i],i);
}
int main(){
	int n=read(),m=read();
	for(int x,y,i=1;i<=m;i++){
		x=read(),y=read();
		add(x,y);add(y,x);
	}
	for(int i=1;i<=n;i++) if(!pt[i]) dep[i]=1,dfs(i,0);
	if(!cnt){
		cout<<m<<"\n";
		for(int i=1;i<=m;i++) cout<<i<<" ";
		return 0; 
	}
	memset(pt,0,sizeof(pt));
	for(int i=1;i<=n;i++) if(!pt[i]) dfs2(i,0);
	if(cnt==1) ans[++cntans]=tmp;
	sort(ans+1,ans+cntans+1);
	cout<<cntans<<"\n";
	for(int i=1;i<=cntans;i++) cout<<ans[i]<<" "; 
	return 0;
}

T2:一个字符串和一个数组,数组某一位的值表示一个字符串的后缀,支持在前端插入一个字符,单点修改数组内某个位置的值,查询数组某个区间内的所有后缀中字典序最小的
解法:显然后缀平衡树,顺便%一发zxyoi考场现推后缀平衡树模板AC
其实可以把串倒过来,然后线段树维护数组每个位置,区间求min,min的比较用二分哈希即可, n l o g 2 n nlog^2n nlog2n但可能会被卡常

#include
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=2e6+5;
int vis[N<<1],head[N<<1],nxt[N<<1],tot=1;
inline void add(int x,int y){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
int dep[N],pt[N],f[N],cnt,tmp;
void dfs(int v,int fa){
	pt[v]=1;
	for(int i=head[v];i;i=nxt[i]){
		if(i==(fa^1)) continue;
		int y=vis[i];
		if(!pt[y]) dep[y]=dep[v]+1,dfs(y,i),f[v]+=f[y];
		else{
			if(dep[y]>dep[v]) continue;
			if((dep[v]-dep[y]+1)&1) ++f[v],--f[y],++cnt,tmp=i>>1;
			else --f[v],++f[y];
		}
	}
}
int ans[N],cntans=0;
inline void dfs2(int v,int fa){
	pt[v]=1;
	if(f[v]==cnt) ans[++cntans]=fa>>1;
	for(int i=head[v];i;i=nxt[i]) if(!pt[vis[i]]) dfs2(vis[i],i);
}
int main(){
	int n=read(),m=read();
	for(int x,y,i=1;i<=m;i++){
		x=read(),y=read();
		add(x,y);add(y,x);
	}
	for(int i=1;i<=n;i++) if(!pt[i]) dep[i]=1,dfs(i,0);
	if(!cnt){
		cout<<m<<"\n";
		for(int i=1;i<=m;i++) cout<<i<<" ";
		return 0; 
	}
	memset(pt,0,sizeof(pt));
	for(int i=1;i<=n;i++) if(!pt[i]) dfs2(i,0);
	if(cnt==1) ans[++cntans]=tmp;
	sort(ans+1,ans+cntans+1);
	cout<<cntans<<"\n";
	for(int i=1;i<=cntans;i++) cout<<ans[i]<<" "; 
	return 0;
}

T3:雅礼WC2019集训traffic

你可能感兴趣的:(线段树,hash,线段树合并)