BZOJ 2322[BeiJing2011]梦想封印 利用"环基"+线性基特征值

Posted TS_Hugh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 2322[BeiJing2011]梦想封印 利用"环基"+线性基特征值相关的知识,希望对你有一定的参考价值。

  很容易想到离线加边并且把环和链拆开搞(就是对于每个终点求出起点到他的路径(其实就是dfs树),然后bzoj2115),而且维护也很简单,然而我们发现不同的终点可能得到相同的值,这就是我们遇到的最大的问题......继续观察,发现两个终点要么得到的值都不同要么得到的值都相同,所以我们就可以判断两个终点的链值的异或值(如果能被此时的"环基"搞出来就可以删掉一个),然后就60分......
  作为一名菜鸡,想到这里就去%题解了,发现我和题解的做法只有去重的时候不同......其实我们就是找到得到的值互不相同的终点的个数,也就是[对于目前的"环基",再插入链值,得到的线性基不同]的终点个数,然后我们发现对于每个终点,判断他们得到的线性基不同就是判断他们在"环基"里插入自己之后自己变成的值(需要经过上下消)不同,这样我们就能通过模拟插入过程得到每个值的"特征值",现在我们只需要找到特征值的种数就可以了(用个set就可以解决)!!!

#include <set>
#include <cstdio>
#include <cstring>
#include <algorithm>
char xB[(1<<15)+10],*xS,*xT;
#define gtc (xS==xT&&(xT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xT)?0:*xS++)
inline void read(int &x){
  register char ch=gtc;
  for(x=0;ch<0||ch>9;ch=gtc);
  for(;ch>=0&&ch<=9;x=(x<<1)+(x<<3)+ch-0,ch=gtc);
}
typedef long long LL;
inline void Read(LL &x){
  register char ch=gtc;
  for(x=0;ch<0||ch>9;ch=gtc);
  for(;ch>=0&&ch<=9;x=(x<<1)+(x<<3)+ch-0,ch=gtc);
}
const int A=61,N=5010,M=20010;
#define bin(a,b) (((a)>>(b))&1)
std::set<LL>::iterator it;
LL temp[N];
int len;
struct Gay{
  int size;LL gay[A];std::set<LL> st;
  inline LL trans(LL x,int begin){
    for(int i=begin;i>=0;--i)
      if(gay[i]&&bin(x,i))x^=gay[i];
    return x;
  }
  inline void put(LL x){st.insert(trans(x,A-1));}
  inline void insert(LL x){
    for(int i=A-1;i>=0;--i){
      if(!bin(x,i))continue;
      if(gay[i])x^=gay[i];
      else{gay[i]=x,++size,len=0;
        for(it=st.begin();it!=st.end();++it)
          temp[++len]=trans(*it,i);
        st.clear();
        for(int j=1;j<=len;++j)st.insert(temp[j]);
        break;}
    }
  }
  inline LL query(){
    return st.size()*(1LL<<size)-1;
  }
}gay;
struct V{int to,next;LL w;}c[M<<1];
struct E{int a,b;LL c;}e[M];
LL dis[N],ans[M];
bool in[N],die[M];
int head[N],t,n,m,Q,sort[M];
inline void add(int x,int y,LL z){c[++t].to=y,c[t].next=head[x],head[x]=t,c[t].w=z;}
inline void dfs(int x,int fa,LL val){
  in[x]=true,dis[x]=val,gay.put(val);
  for(int i=head[x];i;i=c[i].next)
    if(in[c[i].to])gay.insert(c[i].w^dis[x]^dis[c[i].to]);
    else dfs(c[i].to,x,val^c[i].w);
}
int main(){
  read(n),read(m),read(Q);
  register int i;int x;
  for(i=1;i<=m;++i)read(e[i].a),read(e[i].b),Read(e[i].c);
  for(i=1;i<=Q;++i)read(x),sort[i]=x,die[x]=true;
  for(i=1;i<=m;++i)if(!die[i])add(e[i].a,e[i].b,e[i].c),add(e[i].b,e[i].a,e[i].c);
  dfs(1,0,0);
  for(i=Q;i>0;--i){
    ans[i]=gay.query(),x=sort[i];
    add(e[x].a,e[x].b,e[x].c),add(e[x].b,e[x].a,e[x].c);
    if(in[e[x].a]==false&&in[e[x].b]==false)continue;
    if(in[e[x].a]&&in[e[x].b])gay.insert(dis[e[x].a]^dis[e[x].b]^e[x].c);
    else if(in[e[x].a])dfs(e[x].b,e[x].a,dis[e[x].a]^e[x].c);
    else dfs(e[x].a,e[x].b,dis[e[x].b]^e[x].c);
  }printf("%lld\n",gay.query());
  for(i=1;i<=Q;++i)printf("%lld\n",ans[i]);
  return 0;
}

 

以上是关于BZOJ 2322[BeiJing2011]梦想封印 利用"环基"+线性基特征值的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 2322[BeiJing2011]梦想封印 利用"环基"+线性基特征值

bzoj2322 梦想封印

bzoj 2553: [BeiJing2011]禁忌

BZOJ 2460: [BeiJing2011]元素

BZOJ 2460 Beijing2011 元素

bzoj2460[BeiJing2011]元素