省选模拟34

A. 无向图

发现在线性基里能异或出来的数,恰好联通

而且不会有多的数向这里面连边,如果有则一定在线性基内

然后再线段树分治一下

Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define lson rt<<1
#define rson rt<<1|1
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,m;
int a[40],siz;
int A[40][40],SIZ[40];
map<int,int>mp;
struct seg{vector<int>vec;}st[100010*4];
inline bool ins(int x){
	for(int i=m-1;~i;i--) if((x>>i)&1){
		if(!a[i]) return a[i]=x,true;
		else x^=a[i];
	}
	return false;
}
void ins(int rt,int l,int r,int L,int R,int k){
	if(L<=l&&r<=R) return st[rt].vec.emplace_back(k),void();
	int mid=(l+r)>>1;
	if(L<=mid) ins(lson,l,mid,L,R,k);
	if(R>mid) ins(rson,mid+1,r,L,R,k);
}
void dfs(int rt,int l,int r,int K){
	for(auto L:st[rt].vec) if(ins(L)) siz++;
	if(l==r) return printf("%lld\n",1ll<<siz),void();
	int mid=(l+r)>>1;
	for(int i=m-1;~i;i--) A[K][i]=a[i];SIZ[K]=siz;
	dfs(lson,l,mid,K+1);
	for(int i=m-1;~i;i--) a[i]=A[K][i];siz=SIZ[K];
	dfs(rson,mid+1,r,K+1);
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("xor.in","r",stdin);
	freopen("xor.out","w",stdout);
	m=read(),n=read();
	for(int i=1,op,v;i<=n;i++){
		op=read(),v=read();
		if(op==1) mp[v]=i;
		if(op==2){ins(1,1,n,mp[v],i-1,v);mp.erase(v);}
	}
	for(auto L:mp) ins(1,1,n,L.second,n,L.first);
	dfs(1,1,n,1);
	return 0;
}

B. 加与乘

\(A\) 操作最后一次,则 \(A\) 必胜

那么就考虑 \(B\) 获胜的条件

发现只有最后剩下至少 \(1\) 个奇数时, \(B\) 才能获胜

又发现奇数的个数只会变少不会变多

于是 \(A\) 的操作策略就是尽可能的消除奇数

于是只用判断最后能否消完奇数

发现无论如何 \(B\) 都无法将一串连续的 \(1\) 分开

而且 \(B\) 的操作一定不会减少 \(A\) 的操作次数

于是只需要统计出 \(A\) 消完这些连续的 \(1\) 的次数

Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int T,n,m,cnt;
int a[100010];
inline void solve(){
	memset(a,0,sizeof(a));
	n=read();m=read();for(int i=1;i<=n;i++) a[i]=read()&1;cnt=0;
	if(((n^m)&1)==0) return puts("A"),void();
	for(int i=1,j;i<=n;i++) if(a[i]){
		j=i;while(a[j]) j++;
		cnt+=(j-i+1)/2;i=j;
	}
	if(cnt<=(n-1)/2) puts("A");else puts("B");
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	T=read();while(T--) solve();
	return 0;
}

C. 数颜色

先套路的转化一下,每个联通块的点数减去边数等于 \(1\)

那么,询问的答案就是这一段区间覆盖的点数减去覆盖的边数

考虑离线下来做,对于当前维护的右端点 \(r\)

只需要知道有多少点的覆盖时间大于等于询问的 \(l\) 就行了

可以用树状数组维护覆盖时间大于等于 \(i\) 的点的个数

然后再看修改,相当于区间赋值,可以用珂朵莉树实现

每次修改将原来的减去,再加上新的贡献

由于只有区间赋值操作,所有复杂度是正确的

对覆盖的点和边分别做一次就行了

Code
#include<bits/stdc++.h>
#define lowbit(x) x&-x
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,m,q;
int x[100010],y[100010],ans[100010];
int head[100010],ver[200010],to[200010],tot;
int dfn[100010],top[100010],siz[100010],son[100010],fa[100010],dep[100010],clo;
vector<pair<int,int>>vec[100010];
inline void add(int x,int y){ver[++tot]=y;to[tot]=head[x];head[x]=tot;}
void dfs1(int x,int fa,int dep){
	::fa[x]=fa,::dep[x]=dep,siz[x]=1;
	int maxson=-1;
	for(int i=head[x];i;i=to[i]){
		int y=ver[i];if(y==fa) continue;
		dfs1(y,x,dep+1);
		siz[x]+=siz[y];
		if(siz[y]>maxson) son[x]=y,maxson=siz[y];
	}
}
void dfs2(int x,int topf){
	top[x]=topf;dfn[x]=++clo;
	if(!son[x]) return ;
	dfs2(son[x],topf);
	for(int i=head[x];i;i=to[i]){
		int y=ver[i];if(y==fa[x]||y==son[x]) continue;
		dfs2(y,y);
	}
}
namespace BIT{
	int a[100010];
	inline void clear(){memset(a,0,sizeof(a));}
	inline void upd(int x,int k){for(;x;x-=lowbit(x)) a[x]+=k;}
	inline int query(int x){int res=0;for(;x<=m;x+=lowbit(x)) res+=a[x];return res;}
}
namespace ODT{
	struct data{int l,r;mutable int k;inline bool operator<(const data &b)const{return l<b.l;}};
	set<data>st;
	inline void init(){st.clear();st.insert((data){1,n,0});}
	inline set<data>::iterator split(int pos){
		set<data>::iterator iter=st.lower_bound((data){pos,0,0});
		if(iter!=st.end()&&iter->l==pos) return iter;
		iter--;data tmp=*iter;st.erase(iter);
		st.insert((data){tmp.l,pos-1,tmp.k});
		return st.insert((data){pos,tmp.r,tmp.k}).first;
	}
	inline void upd(int l,int r,int k){
		set<data>::iterator itr=split(r+1);
		set<data>::iterator itl=split(l);
		for(set<data>::iterator iter=itl;iter!=itr;iter++) BIT::upd(iter->k,-(iter->r-iter->l+1));
		st.erase(itl,itr);st.insert((data){l,r,k});BIT::upd(k,r-l+1);
	}
}
inline void Tupd(int x,int y,int k,bool op){//0 all 1 lca
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		ODT::upd(dfn[top[x]],dfn[x],k);
		x=fa[top[x]];
	}
	if(op==1&&x==y) return ;if(dep[x]>dep[y]) swap(x,y);
	ODT::upd(dfn[x]+op,dfn[y],k);
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	n=read(),m=read(),q=read();
	for(int i=1,x,y;i<n;i++){x=read(),y=read();add(x,y);add(y,x);}
	dfs1(1,0,1);dfs2(1,1);
	for(int i=1;i<=m;i++) x[i]=read(),y[i]=read();
	for(int i=1,l,r;i<=q;i++){l=read(),r=read();vec[r].emplace_back(make_pair(l,i));}
	ODT::init();
	for(int i=1;i<=m;i++){
		Tupd(x[i],y[i],i,0);
		for(auto L:vec[i]) ans[L.second]+=BIT::query(L.first);
	}
	ODT::init();BIT::clear();
	for(int i=1;i<=m;i++){
		Tupd(x[i],y[i],i,1);
		for(auto L:vec[i]) ans[L.second]-=BIT::query(L.first);
	}
	for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
	return 0;
}
posted @ 2022-03-18 16:03  Max_QAQ  阅读(54)  评论(0编辑  收藏  举报