省选模拟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;
}