一、题目
二、解法
首先做一下这道题:最大XOR和路径,是这题的弱化版。
首先介绍一下线段树分治,就是把每一个修改的影响的询问区间打到线段树上(类比线段树区间修改),然后再访问一遍线段树,期间加入在这个点上的修改,到 l = r l=r l=r时就可以拿到询问的值了。
具体可以维护一个并查集,我们不能路径压缩,但是可以通过启发式合并来保证复杂度。如果 ( u , v ) (u,v) (u,v)是联通的话,那么就加入这个环,否则启发式合并,合并 ( f u , f v ) (fu,fv) (fu,fv)时边权设置为 c ⊕ d i s ( f u , u ) ⊕ d i s ( f v , v ) c\oplus dis(fu,u)\oplus dis(fv,v) c⊕dis(fu,u)⊕dis(fv,v),那么 v v v到 f u fu fu的距离就正好是 c ⊕ d i s ( f u , u ) c\oplus dis(fu,u) c⊕dis(fu,u),然后我们还需要写一个回退(不难)
询问的话用线性基,方法就是弱化版的方案,贴个代码。
#include <cstdio>
#include <iostream>
#include <vector>
#include <stack>
#include <map>
using namespace std;
const int M = 200005;
#define mp make_pair
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,k,q,tot,bg[2*M],ed[2*M],qu[M],qv[M],fa[M],dep[M],dis[M];
map<pair<int,int> ,int> Mp;
struct edge
{
int u,v,c;
}e[2*M];vector<edge> tr[M<<2];
struct node
{
int w[40];
void insert(int x)
{
for(int i=30;i>=0;i--)
{
if(!(x>>i)) continue;
if(!w[i]){w[i]=x;return ;}
x^=w[i];
}
}
int query(int x)
{
for(int i=30;i>=0;i--)
if((x^w[i])<x) x^=w[i];
return x;
}
}a;
void ins(int i,int l,int r,int L,int R,edge e)
{
if(L>r || l>R) return ;
if(L<=l && r<=R)
return (void)tr[i].push_back(e);
int mid=(l+r)>>1;
ins(i<<1,l,mid,L,R,e);
ins(i<<1|1,mid+1,r,L,R,e);
}
int find(int x)
{
if(x==fa[x]) return x;
return find(fa[x]);
}
int get(int x)
{
if(x==fa[x]) return 0;
return dis[x]^get(fa[x]);
}
void cdq(int p,int l,int r,node a)
{
stack<edge> s;edge t;
for(int i=0;i<tr[p].size();i++)
{
int u=tr[p][i].u,v=tr[p][i].v,c=tr[p][i].c^get(u)^get(v);
int fu=find(u),fv=find(v);
if(fu==fv)
a.insert(c);
else
{
if(dep[fu]>dep[fv]) swap(fu,fv),swap(u,v);
t=edge{fu,fv,0},fa[fu]=fv,dis[fu]=c;
if(dep[fu]==dep[fv]) dep[fv]++,t.c=1;
s.push(t);
}
}
int mid=(l+r)>>1;
if(l==r) printf("%d\n",a.query(get(qu[l])^get(qv[l])));
else cdq(p<<1,l,mid,a),cdq(p<<1|1,mid+1,r,a);
while(!s.empty())
dis[fa[s.top().u]=s.top().u]=0,dep[s.top().v]-=s.top().c,s.pop();
}
signed main()
{
n=read();m=read();k=1;
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=m;i++)
{
int u=read(),v=read(),c=read();
e[i]=edge{u,v,c};
bg[i]=1;ed[i]=-1;
Mp[mp(u,v)]=i;
}
q=read();
while(q--)
{
int op=read(),u=read(),v=read();
if(op==1)
{
int c=read();
e[++m]=edge{u,v,c};
bg[m]=k;ed[m]=-1;
Mp[mp(u,v)]=m;
}
if(op==2)
ed[Mp[mp(u,v)]]=k-1;
if(op==3)
{
qu[k]=u;qv[k]=v,k++;
}
}
k--;
for(int i=1;i<=m;i++)
if(ed[i]==-1) ed[i]=k;
for(int i=1;i<=m;i++)
if(bg[i]<=ed[i]) ins(1,1,k,bg[i],ed[i],e[i]);
cdq(1,1,k,a);
}
有一道差不多的题:八纵八横,只不过这个题要用 bitset \text{bitset} bitset,就贴个代码吧。
#include <cstdio>
#include <bitset>
#include <vector>
#include <iostream>
using namespace std;
#define bs bitset<1005>
const int M = 2005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,k,q,tp,a[M],fa[M],dep[M],st[M];char s[10];
bs dis[M];
struct node
{
int u,v;bs c;
}e[M];vector<node> v[2*M];
struct basis
{
bs p[M];
void ins(bs x)
{
for(int i=1000;i>=0;i--)
{
if(!x.test(i)) continue;
if(p[i].none()) {p[i]=x;return ;}
x^=p[i];
}
}
bs ask()
{
bs t;
for(int i=1000;i>=0;i--)
if(!t[i])
t^=p[i];
return t;
}
}emp;
void print(bs a)
{
int f=0;
for(int i=1000;i>=0;i--)
if(a[i]==0 && f==0);
else f=1,cout<<a[i];
puts("");
}
void ins(int i,int l,int r,int L,int R,node x)
{
if(L>r || l>R) return ;
if(L<=l && r<=R)
{
v[i].push_back(x);
return ;
}
int mid=(l+r)>>1;
ins(i<<1,l,mid,L,R,x);
ins(i<<1|1,mid+1,r,L,R,x);
}
int find(int x)
{
return x==fa[x]?x:find(fa[x]);
}
bs get(int x)
{
return x==fa[x]?0:dis[x]^get(fa[x]);
}
void back(int t)
{
while(tp>t)
{
int y=st[tp--],x=st[tp--];
if(y<0) dep[x]--,y-=y;
fa[y]=y;dis[y]=0;
}
}
void ask(int p,int l,int r,basis a)
{
int cur=tp;
for(int i=0;i<v[p].size();i++)
{
int x=v[p][i].u,y=v[p][i].v,fu=find(x),fv=find(y);
bs c=v[p][i].c^get(x)^get(y);
if(find(x)==find(y)) a.ins(c);
else
{
if(dep[fu]<dep[fv]) swap(fu,fv);
fa[fv]=fu;dis[fv]=c;st[++tp]=fu;st[++tp]=fv;
if(dep[fu]==dep[fv]) dep[fu]++,st[tp]*=-1;
}
}
if(l==r)
{
print(a.ask());
back(cur);
return ;
}
int mid=(l+r)>>1;
ask(p<<1,l,mid,a);
ask(p<<1|1,mid+1,r,a);
back(cur);
}
int main()
{
n=read();m=read();q=read();
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=m;i++)
{
e[i].u=read();e[i].v=read();cin>>e[i].c;
ins(1,0,q,0,q,e[i]);
}
for(int i=1;i<=q;i++)
{
scanf("%s",s);
if(s[0]=='A')
{
e[++k].u=read();e[k].v=read();cin>>e[k].c;
a[k]=i;
}
if(s[0]=='C' && s[1]=='a')
{
int t=read();
ins(1,0,q,a[t],i-1,e[t]);a[t]=0;
}
if(s[0]=='C' && s[1]=='h')
{
int t=read();
ins(1,0,q,a[t],i-1,e[t]);a[t]=i;
cin>>e[t].c;
}
}
for(int i=1;i<=k;i++)
if(a[i]) ins(1,0,q,a[i],q,e[i]);
ask(1,0,q,emp);
}