【洛谷P3733】八纵八横
题目
题目链接:https://www.luogu.com.cn/problem/P3733
Anihc 国有 \(n\) 个城市,这 \(n\) 个城市从 \(1\) 到 \(n\) 编号,\(1\) 号城市为首都。城市间初始时有 \(m\) 条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路的两端都是城市(可能两端是同一个城市),保证任意两个城市都可以通过高速公路互达。
国正在筹划“八纵八横”的高铁建设计划,计划要修建一些高速铁路,每条高速铁路两端也都是城市(可能两端是同一个城市),也都有一个非负整数的经济影响因子。国家还计划在“八纵八横”计划建成之后,将“一带一路”扩展为“一带_路一环”,增加“内陆城市经济环”即选择一条从首都出发沿若一系列高铁与高速公路走的路径,每条高铁或高速公路可以经过多次,每座城市也可以经过多次,最后路径又在首都结束。令“内陆城市经济环”的 GDP 为依次将这条路径上所经过的高铁或高速公路的经济影响因子异或起来(一条路经过多次则会被计算多次)。
现在 Anihc 在会议上讨论“八纵八横”的建设计划方案,他们会不断地修改计划方案,希望你能实时反馈对于当前的“八纵八横”的建设计划的方案“内陆城市经济环”的最大是多少。
初始时,八纵八横计划中不包含任何一条高铁,有以下 \(3\) 种操作:
Add x y z
:在计划中给在城市 \(x\) 和城市 \(y\) 之间建设一条高铁,其经济影响因子为 \(z\),如果这是第 \(k\) 个Add
操作,则将这条高铁命名为 \(k\) 号高铁。Cancel k
:将计划中的 \(k\) 号高铁取消掉,保证此时 \(k\) 号高铁一定存在Change k z
:表示将第 \(k\) 号高铁的经济影响因子更改为 \(z\),保证此时 \(k\) 号高铁一定存在。
\(n,m\leq 500,Q,len\leq 1000\)。\(len\) 是边权二进制下位数最大值。
思路
这题目看着我头晕。。。
首先如果没有修改,那么就是线性基的板子题。显然答案路径就是若干个环。线性基求异或最大值即可。
有了修改之后,发现每次的修改都是一段区间,所以直接线段树分治就好了。维护比较大需要用 bitset。
时间复杂度 \(O(\frac{Q\log Q\log n\times len}{\omega})\),空间复杂度 \(O(\frac{len^2\log n}{\omega})\)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=1010,LG=10;
int n,m,Q,tot,head[N],last[N],U[N],V[N];
bitset<N> dis[N];
char s[N],opt[10];
bool vis[N];
struct edge
{
int next,to;
bitset<N> dis;
}e[N*2];
void add(int from,int to,bitset<N> d)
{
e[++tot]=(edge){head[from],to,d};
head[from]=tot;
}
void work(int id)
{
dis[id].reset();
int len=strlen(s);
for (int j=0;j<len;j++)
dis[id][len-j-1]=s[j]-48;
}
void dfs(int x)
{
vis[x]=1;
for (int i=head[x];~i;i=e[i].next)
{
int v=e[i].to;
if (!vis[v])
{
dis[v]=dis[x]^e[i].dis;
dfs(v);
}
}
}
struct VectorSpace
{
bitset<N> c[N];
void ins(bitset<N> v)
{
for (int i=N-1;i>=0;i--)
if (v[i])
{
if (c[i].none()) { c[i]=v; break; }
v^=c[i];
}
}
void query()
{
bool flag=0;
bitset<N> v; v.reset();
for (int i=N-1;i>=0;i--)
{
if (!v[i]) v^=c[i];
if (v[i]) flag=1;
if (flag) cout<<v[i];
}
cout<<"\n";
}
}vs[LG+1];
struct SegTree
{
vector<edge> e[N*4];
void update(int x,int l,int r,int ql,int qr,edge v)
{
if (ql<=l && qr>=r)
return (void)e[x].push_back(v);
int mid=(l+r)>>1;
if (ql<=mid) update(x*2,l,mid,ql,qr,v);
if (qr>mid) update(x*2+1,mid+1,r,ql,qr,v);
}
void query(int x,int l,int r,int d)
{
if (d) vs[d]=vs[d-1];
for (int i=0;i<e[x].size();i++)
{
int u=e[x][i].next,v=e[x][i].to;
vs[d].ins(dis[u]^dis[v]^e[x][i].dis);
}
if (l==r) { vs[d].query(); return; }
int mid=(l+r)>>1;
query(x*2,l,mid,d+1); query(x*2+1,mid+1,r,d+1);
}
}seg;
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d%d",&n,&m,&Q);
for (int i=1,x,y;i<=m;i++)
{
scanf("%d%d%s",&x,&y,s);
work(0);
add(x,y,dis[0]); add(y,x,dis[0]);
}
for (int i=1,x,j=0;i<=Q;i++)
{
scanf("%s",opt);
if (opt[1]=='d')
{
last[++j]=i;
scanf("%d%d%s",&U[j],&V[j],s);
work(j);
}
if (opt[1]=='h')
{
scanf("%d%s",&x,s);
seg.update(1,1,Q,last[x],i-1,(edge){U[x],V[x],dis[x]});
work(x); last[x]=i;
}
if (opt[1]=='a')
{
scanf("%d",&x);
seg.update(1,1,Q,last[x],i-1,(edge){U[x],V[x],dis[x]});
last[x]=0;
}
}
for (int i=1;i<=Q;i++)
if (last[i]) seg.update(1,1,Q,last[i],Q,(edge){U[i],V[i],dis[i]});
dis[1].reset();
dfs(1);
for (int i=1;i<=tot;i+=2)
vs[0].ins(dis[e[i].to]^dis[e[i+1].to]^e[i].dis);
vs[0].query();
if (Q) seg.query(1,1,Q,0);
return 0;
}