#3189. 八纵八横(c)

题目描述

Anihc 国有 n n n 个城市,这 n n n 个城市从 1 1 1 ~ n n n 编号, 1 1 1 号城市为首都。城市间初始时有 m m m 条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路的两端都是城市(可能两端是同一个城市),保证任意两个城市都可以通过高速公路互达。

Anihc 国正在筹划「八纵八横」的高铁建设计划,计划要修建一些高速铁路,每条高速铁路两端也都是城市(可能两端是同一个城市),也都有一个非负整数的经济影响因子。国家还计划在「八纵八横」计划建成之后,将「一带一路」扩展为「一带一路一环」,增加「内陆城市经济环」即选择一条从首都出发沿若一系列高铁与高速公路走的路径,每条高铁或高速公路可以经过多次,每座城市也可以经过多次,最后路径又在首都结束。令「内陆城市经济环」的 GDP 为依次将这条路径上所经过的高铁或高速公路的经济影响因子异或起来(一条路经过多次则会被计算多次)。

现在 Anihc 在会议上讨论「八纵八横」的建设计划方案,他们会不断地修改计划方案,希望你能实时反馈对于当前的「八纵八横」的建设计划的方案「内陆城市经济环」的最大是多少。

初始时,八纵八横计划中不包含任何—条高铁,有以下三种操作:

Add x y z

在计划中给在城市 x x x 和城市 y y y 之间建设一条高铁,其经济影响因子为 z z z ,如果这是第 k k k 个 Add 操作,则将这条高铁命名为 k k k 号高铁。

Cancel k

将计划中的 k k k 号高铁取消掉,保证此时 k k k 号高铁一定存在。

Change k z

表示将第 k k k 号高铁的经济影响因子更改为 z z z ,保证此时 k k k 号高铁一定存在。

题解

还是一样的套路,图中的环是可以取出的,所以维护一个环的线性基即可。

然后线性基是不能撤销的,于是我们考虑线段树分治即可。这里异或可以用 bitset \text{bitset} bitset 维护。

代码
#include <bits/stdc++.h>
#define B bitset<1000>
using namespace std;
const int N=1002;char ch[N];
int n,m,q,t=1,hd[N],V[N],nx[N],X[N],Y[N];
B K,W[N],a[N],b[N];bool vis[N];
struct O{int u,v;B w;}h[N];
vector<O>g[N<<2];vector<int>S[N<<2];
void add(int u,int v,B w){
	nx[++t]=hd[u];V[hd[u]=t]=v;W[t]=w;
}
B Get(){
	int l=strlen(ch);K.reset();
	for (int i=0,j=l-1;~j;j--,i++)
		if (ch[j]^48) K[i]=1;return K;
}
int ins(B x){
	for (int i=999;~i;i--) if (x[i]){
		if (b[i][i]) x^=b[i];
		else{b[i]=x;return i;}
	}
	return -1;
}
void dfs(int x,int fr){
	vis[x]=1;
	for (int i=hd[x];i;i=nx[i]){
		if (i==(fr^1)) continue;
		if (vis[V[i]]) ins(a[x]^a[V[i]]^W[i]);
		else a[V[i]]=a[x]^W[i],dfs(V[i],i);
	}
}
#define Ls k<<1
#define Rs k<<1|1
#define mid ((l+r)>>1)
void upd(int k,int l,int r,int L,int R,O v){
	if (L<=l && r<=R){
		g[k].push_back(v);return;
	}
	if (mid>=L) upd(Ls,l,mid,L,R,v);
	if (mid<R) upd(Rs,mid+1,r,L,R,v);
}
void qry(int k,int l,int r){
	int z=g[k].size();
	for (int v,i=0;i<z;i++){
		v=ins(a[g[k][i].u]^a[g[k][i].v]^g[k][i].w);
		if (~v) S[k].push_back(v);
	}
	if (l==r){
		K.reset();int v=0;
		for (int i=999;~i;i--){
			if (K[i]^b[i][i]) K^=b[i];
			if (K[i]) putchar(49),v=1;
			else if (v) putchar(48);
		}
		putchar('\n');
	}
	else qry(Ls,l,mid),qry(Rs,mid+1,r);
	z=S[k].size();
	for (int i=z-1;~i;i--)
		b[S[k][i]].reset();
}
int main(){
	cin>>n>>m>>q;
	for (int x,y,i=1;i<=m;i++)
		scanf("%d%d%s",&x,&y,ch),
		add(x,y,Get()),add(y,x,Get());
	dfs(1,t=0);
	for (int x,y,i=1;i<=q;i++){
		scanf("%s",ch);
		if (ch[0]=='A')
			scanf("%d%d%s",&x,&y,ch),
			X[++t]=i,Y[t]=-1,h[t]=(O){x,y,Get()};
		else if (ch[1]=='a')
			scanf("%d",&x),
			upd(1,0,q,X[x],Y[x]=i-1,h[x]);
		else scanf("%d%s",&x,ch),
			upd(1,0,q,X[x],i-1,h[x]),
			X[x]=i,h[x].w=Get();
	}
	for (int i=1;i<=t;i++)
		if (!~Y[i]) upd(1,0,q,X[i],q,h[i]);
	qry(1,0,q);return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值