BZOJ4644 : 经典傻逼题

本文介绍了一种解决图论中最大异或和问题的方法,通过维护线性基并结合时间分治策略来优化算法效率。利用bitset进行加速,并采用Four Russian Method进一步提升插入操作的性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

设每个点的权值为和它相连的所有边的权值的异或和,那么等价于选若干个点,使得点权异或和最大,这显然只需要维护一组线性基,然后从高位到低位贪心选取即可。

对于本题,因为有修改操作,所以考虑按时间分治,并用bitset加速,时间复杂度$O(\frac{m\log mL^2}{64})$。

针对插入操作,可以用Four Russian Method进一步优化。

将$1000$个基$4$个一组分成$250$组,每组对于$2^4$种可能的插入向量预处理出消元后的结果。

那么插入只需要$250$次消元,插入之后重新预处理那块即可。

时间复杂度$O(\frac{m\log mL^2}{64\log L})$。

 

#include<cstdio>
#include<cstring>
#include<bitset>
#include<vector>
#define N 505
using namespace std;
typedef bitset<1000>bs;
int n,m,i,x,y,cnt,vis[N],cur,idb[N],idg[N];
bs B[1000],fin,w,a[N],q[2010],pb[N];
struct P{int l,r,p;P(int _l,int _r,int _p){l=_l,r=_r,p=_p;}};
vector<P>V;
struct Block{
  bs a[16];int b[16];
  void build(int x){
    for(int S=1;S<16;S++){
      int j;
      for(j=3;~j;j--)if(S>>j&1)break;
      if(B[x+3-j][x+3-j]){
        a[S]=B[x+3-j];
        int ret=S;
        for(int i=j;~i;i--)if(B[x+3-j][x+3-i])ret^=1<<i;
        if(ret)a[S]^=a[ret],b[S]=b[ret];else b[S]=0;
      }else a[S].reset(),b[S]=1<<j;
    }
  }
}G[250],pg[N];
inline void ins(bs x){
  int i,j,k;
  for(i=j=0;i<250;i++){
    int S=0;
    for(k=0;k<4;j++,k++){
      S<<=1;
      if(x[j])S++;
    }
    if(!S)continue;
    x^=G[i].a[S];
    if(G[i].b[S]){
      int k=j-1-__builtin_ctz(G[i].b[S]);
      cur++;
      idb[cur]=k;
      idg[cur]=i;
      pb[cur]=B[k];
      pg[cur]=G[i];
      B[k]=x;
      G[i].build(j-4);
      break;
    }
  }
}
inline void get(){
  static char s[1010];
  scanf("%s",s);
  w.reset();
  int n=strlen(s);
  for(int i=0;i<n;i++)if(s[i]=='1')w[1000+i-n]=1;
}
inline void retrace(int x){
  while(cur>x){
    B[idb[cur]]=pb[cur];
    G[idg[cur]]=pg[cur];
    cur--;
  }
}
void solve(int l,int r,vector<P>V){
  int t=cur;
  vector<P>S;
  for(vector<P>::iterator it=V.begin();it!=V.end();it++)
    if(it->l<=l&&r<=it->r)ins(q[it->p]);
    else S.push_back(*it);
  if(l==r){
    fin.reset();
    for(int i=0;i<1000;i++)if(!fin[i])if(B[i][i])fin^=B[i];
    bool flag=0;
    for(int i=0;i<1000;i++)if(fin[i])putchar('1'),flag=1;else if(flag)putchar('0');
    if(!flag)putchar('0');
    puts("");
    retrace(t);
    return;
  }
  int mid=(l+r)>>1;
  solve(l,mid,S),solve(mid+1,r,S);
  retrace(t);
}
int main(){
  scanf("%d",&n);
  scanf("%d%d",&n,&m);
  for(i=1;i<=m;i++){
    scanf("%d%d",&x,&y);
    get();
    x--,y--;
    if(vis[x])q[++cnt]=a[x],V.push_back(P(vis[x],i-1,cnt));
    if(vis[y])q[++cnt]=a[y],V.push_back(P(vis[y],i-1,cnt));
    vis[x]=vis[y]=i;
    a[x]^=w,a[y]^=w;
  }
  for(i=0;i<n;i++)if(vis[i])q[++cnt]=a[i],V.push_back(P(vis[i],m,cnt));
  for(i=0;i<250;i++)G[i].build(i<<2);
  solve(1,m,V);
  return 0;
}

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值