题面

题面

题解

观察到题目中的 “内陆经济环” 不好处理,因此我们把它拆成 “内陆经济链”。

对于1号节点,我们创建一个它的复制节点n + 1号节点,这个节点继承1号节点的所有边,可以发现,一个1到1的内陆经济环,和一个1到n + 1的内陆经济链是等价的,因此我们只需要考虑如何在一个变化的图上维护一个点到另一个点的最大xor和即可。

观察到删边只会删去后来加入的边,所以就很好处理了,我们用线段树分治(时间分治)来维护。

具体求从1到n + 1的最大xor和的方法参见此题(是一个常见套路,就不在赘述了):[WC2011]最大XOR和路径 线性基

于是我们的目的仅仅是维护当前图中所有简单环构成的线性基。

因为线段树分治最深也就log,所以同时维护log个线性基的时间空间都还是可承受的。

因此我们每到一个新节点就建一个新的线性基,然后加入新增的环,退出时再删去即可。

考虑如何快速求新增的环。

因为在dfs树上,一条非树边代表一个简单环,所以一个新增的,连接x ---> y 的边最多带来一个新环,而这个新环,肯定是经过这条新边,从x走到y,再走回x的路径所构成的一个环。

因为xor的特性,所以我们可以用x到rot的路径 + y到rot的路径 + 新边来异或出这个环的异或值。

因此我们只需要知道一个点新增了哪些边就可以了。

#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 550
#define ac 2100
#define maxn 8000
#define maxm 2010000 int n, m, all, cnt;
int dead[ac], start[ac], id[ac];
int Head[AC], date[ac], Next[ac], tot;
bitset<1100> len[ac], ans[ac], val[AC], link[maxn];
struct road{int x, y, id;bitset<1100> v;}way[ac];//注意一条边会且只会带来一个环(因为原图联通)
bool vis[AC];
char ss[ac]; //int s[AC], top;//存下待分配的线性基编号
struct basis{//第几层就用第几个线性基
bitset<1100> f[1100];//第1000位为最高位
void clear() {for(R i = 1; i <= 1000; i += 2) f[i] = f[i + 1] = 0;} void ins(bitset<1100> x)
{
for(R i = 1000; i; i --)
{
if(!x[i]) continue;
if(f[i] == 0) {f[i] = x; break;}
else x ^= f[i];
}
} }f[50];//最多同时用到log个线性基 inline int read()
{
int x = 0;char c = getchar();
while(c > '9' || c < '0') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x;
} /*inline void add_new(int f, int w)//f为线段树上的一个点,w是一条边的编号
{date_[++ tot_] = w, Next_[tot_] = Head_[f], Head_[f] = tot_;}*/ inline void add(int f, int w, bitset<1100> S)
{
date[++ tot] = w, Next[tot] = Head[f], Head[f] = tot, len[tot] = S;
date[++ tot] = f, Next[tot] = Head[w], Head[w] = tot, len[tot] = S;
} void dfs(int x, bitset<1100> have)//找最初的环,
{
vis[x] = true, val[x] = have;
for(R i = Head[x]; i; i = Next[i])
{
int now = date[i];
if(vis[now]) f[0].ins(have ^ len[i] ^ val[now]);
else dfs(now, have ^ len[i]);
}
} void change(int x, int l, int r, int ll, int rr, int w)//给[ll, rr]加入一条边,其编号为w
{
if(l == ll && r == rr){link[x][w] = true; return ;}
int mid = (l + r) >> 1;
if(rr <= mid) change(x << 1, l, mid, ll, rr, w);
else if(ll > mid) change((x << 1) + 1, mid + 1, r, ll, rr, w);
else
{
change(x << 1, l, mid, ll, mid, w);
change((x << 1) + 1, mid + 1, r, mid + 1, rr, w);
}
} void solve(int x, int l, int r, int dep)
{
f[dep] = f[dep - 1];
for(R i = 1; i <= all; i ++)
if(link[x][i]) f[dep].ins(val[way[i].x] ^ val[way[i].y] ^ way[i].v);
if(l == r)
{
ans[l] = val[n + 1];
for(R i = 1000; i; i --)
if(ans[l][i] == 0) ans[l] ^= f[dep].f[i];
return ;
}
int mid = (l + r) >> 1;
solve(x << 1, l, mid, dep + 1);
solve((x << 1) + 1, mid + 1, r, dep + 1);
} bitset<1100> get()
{
bitset<1100> tmp;
scanf("%s", ss + 1); int t = strlen(ss + 1);
for(R j = t, l = 1; j; j --, l ++) tmp[l] = (ss[j] == '1'); //存下边权
return tmp;
} void pre()
{
n = read(), m = read(), all = read();
bitset<1100> tmp;
for(R i = 1; i <= m; i ++)
{
int x = read(), y = read();
if(x > y) swap(x, y);
tmp = get();
add(x, y, tmp);
if(x == 1) add(n + 1, y, tmp);
}
} void build()
{
for(R i = 1; i <= all; i ++)
{
scanf("%s", ss + 1);
if(ss[1] == 'A') //加边
{
id[++ cnt] = i;//id[x]存下边x当前是谁在承受修改
start[i] = i, dead[i] = all;
way[i].x = read(), way[i].y = read(), way[i].v = get();
}
else if(ss[2] == 'a') {dead[id[read()]] = i - 1;}//删边
else //修改边权,看做删去一条旧边生成一条新边,并且新边承担后面旧边的修改
{
int x = read();//承担旧边的修改,并删除旧边
way[i] = way[id[x]], way[i].v = get();
start[i] = i, dead[i] = all, dead[id[x]] = i - 1, id[x] = i;//除了初始化id[x]外,其他的地方都要用到id[x]
}//所以id[x] = i放在最后面修改,在前面的x都要用id[x]代替
}
for(R i = 1; i <= all; i ++)
if(start[i]) change(1, 1, all, start[i], dead[i], i);
} void work()
{
for(R i = 1000; i; i --)
if(!ans[0][i]) ans[0] ^= f[0].f[i];
for(R i = 0; i <= all; i ++)
{
int l = 1000;
while(!ans[i][l] && l) -- l;
for(R j = l; j; j --) printf("%c", (ans[i][j] == 1) ? '1' : '0');
if(!l) printf("0");
printf("\n");
}
} int main()
{
// freopen("in.in", "r", stdin);
pre();
dfs(1, ans[0]);//反正此时ans[0]是空的
build();
if(all) solve(1, 1, all, 1);
work();
// fclose(stdin);
return 0;
}

[HAOI2017]八纵八横 线性基的更多相关文章

  1. 洛谷.3733.[HAOI2017]八纵八横(线性基 线段树分治 bitset)

    LOJ 洛谷 最基本的思路同BZOJ2115 Xor,将图中所有环的异或和插入线性基,求一下线性基中数的异或最大值. 用bitset优化一下,暴力的复杂度是\(O(\frac{qmL^2}{w})\) ...

  2. loj#2312. 「HAOI2017」八纵八横(线性基 线段树分治)

    题意 题目链接 Sol 线性基+线段树分治板子题.. 调起来有点自闭.. #include<bits/stdc++.h> #define fi first #define se secon ...

  3. 【Luogu3733】[HAOI2017]八纵八横(线性基,线段树分治)

    [Luogu3733][HAOI2017]八纵八横(线性基,线段树分治) 题面 洛谷 题解 看到求异或最大值显然就是线性基了,所以只需要把所有环给找出来丢进线性基里就行了. 然后线性基不资磁撤销?线段 ...

  4. 【线段树分治 线性基】luoguP3733 [HAOI2017]八纵八横

    不知道为什么bzoj没有HAOI2017 题目描述 Anihc国有n个城市,这n个城市从1~n编号,1号城市为首都.城市间初始时有m条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路 ...

  5. LOJ2312 LUOGU-P3733「HAOI2017」八纵八横 (异或线性基、生成树、线段树分治)

    八纵八横 题目描述 Anihc国有n个城市,这n个城市从1~n编号,1号城市为首都.城市间初始时有m条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路的两端都是城市(可能两端是同一个 ...

  6. 【luogu3733】【HAOI2017】 八纵八横 (线段树分治+线性基)

    Descroption 原题链接 给你一个\(n\)个点的图,有重边有自环保证连通,最开始有\(m\)条固定的边,要求你支持加边删边改边(均不涉及最初的\(m\)条边),每一次操作都求出图中经过\(1 ...

  7. LOJ 2312(洛谷 3733) 「HAOI2017」八纵八横——线段树分治+线性基+bitset

    题目:https://loj.ac/problem/2312 https://www.luogu.org/problemnew/show/P3733 原本以为要线段树分治+LCT,查了查发现环上的值直 ...

  8. BZOJ 2844 albus就是要第一个出场 ——高斯消元 线性基

    [题目分析] 高斯消元求线性基. 题目本身不难,但是两种维护线性基的方法引起了我的思考. void gauss(){ k=n; F(i,1,n){ F(j,i+1,n) if (a[j]>a[i ...

  9. BZOJ 2115 [Wc2011] Xor ——线性基

    [题目分析] 显然,一个路径走过两边是不需要计算的,所以我么找到一条1-n的路径,然后向该异或值不断异或简单环即可. 但是找出所有简单环是相当复杂的,我们只需要dfs一遍,找出所有的环路即可,因为所有 ...

随机推荐

  1. angularJS ng-repeat中的directive 动态加载template

    有个需求,想实现一个html组件,传入不同的typeId,渲染出不同的表单元素. <div ng-repeat="field in vm.data"> <magi ...

  2. 三、Django安装和流程

    一.MVC模式 MVC(Model-View-Controller),中文名“模型-视图-控制器”,是一个好的Web应用开发所遵循的模式,它有利于把Web应用的代码分解为易于管理的功能模块. M:Mo ...

  3. cocos2dx2.0 帧动画的创建和播放过程 深入分析

    一.帧动画的创建过程帧动画的实现有四个不可或缺的类,如下:1.CCSpriteFrame:精灵帧信息.存储帧动画的每一帧的纹理基本信息. class CC_DLL CCSpriteFrame : pu ...

  4. maven 手动安装jar包

    1.问题 maven有时候在pom文件引入jar包会报错,所以可以通过手动导入jar包的方式导入. 2.解决: 通过maven命令导入jar包, mvn install:install-file -D ...

  5. bootstrap form样式及数据提交

    1.基本form布局 想要把form表单弄成两列的表格样式,奈何前端不太懂,记录下样式便于下次使用. form-group :增加盒子的下边界 form-control: 充满整个父元素,并且有换行作 ...

  6. 详细讲解 A/B 测试关键步骤,快来检查下还有哪些疏漏的知识点

    作为一种对照实验方法,A/B 测试通过比较两个 (或多个) 不同版本之间的差异来验证假设是否正确.该方法将特定测试组从实验其余部分中独立出来,从而得出可靠结果.在被测人不知情且测试场景真实的情况下,A ...

  7. 第七章移动互联网与移动IP

    第七章移动互联网与移动IP 本章延续前几章节,对该章节内容进行归纳总结. 文章中的Why表示产生的背景,也就是说为什么会产生该技术,What表示该技术是什么,How表示该技术是如何使用的.以下将用字母 ...

  8. CSP201403-3:命令行选项

    引言:CSP(http://www.cspro.org/lead/application/ccf/login.jsp)是由中国计算机学会(CCF)发起的"计算机职业资格认证"考试, ...

  9. Linux内核学习笔记(5)-- 进程调度概述

    进程调度程序是多任务操作系统的基础,它是确保进程能有效工作的一个内核子系统,负责决定哪个进程投入运行.何时运行以及运行多长时间.只有通过进程调度程序的合理调度,系统资源才能够最大限度地发挥作用,多进程 ...

  10. 152.[LeetCode] Maximum Product Subarray

    Given an integer array nums, find the contiguous subarray within an array (containing at least one n ...