[HAOI2017]八纵八横 线性基
题面
题解
观察到题目中的 “内陆经济环” 不好处理,因此我们把它拆成 “内陆经济链”。
对于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]八纵八横 线性基的更多相关文章
- 洛谷.3733.[HAOI2017]八纵八横(线性基 线段树分治 bitset)
		LOJ 洛谷 最基本的思路同BZOJ2115 Xor,将图中所有环的异或和插入线性基,求一下线性基中数的异或最大值. 用bitset优化一下,暴力的复杂度是\(O(\frac{qmL^2}{w})\) ... 
- loj#2312. 「HAOI2017」八纵八横(线性基 线段树分治)
		题意 题目链接 Sol 线性基+线段树分治板子题.. 调起来有点自闭.. #include<bits/stdc++.h> #define fi first #define se secon ... 
- 【Luogu3733】[HAOI2017]八纵八横(线性基,线段树分治)
		[Luogu3733][HAOI2017]八纵八横(线性基,线段树分治) 题面 洛谷 题解 看到求异或最大值显然就是线性基了,所以只需要把所有环给找出来丢进线性基里就行了. 然后线性基不资磁撤销?线段 ... 
- 【线段树分治 线性基】luoguP3733 [HAOI2017]八纵八横
		不知道为什么bzoj没有HAOI2017 题目描述 Anihc国有n个城市,这n个城市从1~n编号,1号城市为首都.城市间初始时有m条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路 ... 
- LOJ2312 LUOGU-P3733「HAOI2017」八纵八横 (异或线性基、生成树、线段树分治)
		八纵八横 题目描述 Anihc国有n个城市,这n个城市从1~n编号,1号城市为首都.城市间初始时有m条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路的两端都是城市(可能两端是同一个 ... 
- 【luogu3733】【HAOI2017】 八纵八横 (线段树分治+线性基)
		Descroption 原题链接 给你一个\(n\)个点的图,有重边有自环保证连通,最开始有\(m\)条固定的边,要求你支持加边删边改边(均不涉及最初的\(m\)条边),每一次操作都求出图中经过\(1 ... 
- LOJ 2312(洛谷 3733) 「HAOI2017」八纵八横——线段树分治+线性基+bitset
		题目:https://loj.ac/problem/2312 https://www.luogu.org/problemnew/show/P3733 原本以为要线段树分治+LCT,查了查发现环上的值直 ... 
- BZOJ 2844 albus就是要第一个出场 ——高斯消元 线性基
		[题目分析] 高斯消元求线性基. 题目本身不难,但是两种维护线性基的方法引起了我的思考. void gauss(){ k=n; F(i,1,n){ F(j,i+1,n) if (a[j]>a[i ... 
- BZOJ 2115 [Wc2011] Xor ——线性基
		[题目分析] 显然,一个路径走过两边是不需要计算的,所以我么找到一条1-n的路径,然后向该异或值不断异或简单环即可. 但是找出所有简单环是相当复杂的,我们只需要dfs一遍,找出所有的环路即可,因为所有 ... 
随机推荐
- 我们一起学习WCF 第五篇数据协定和消息协定
			A:数据协定(“数据协定”是在服务与客户端之间达成的正式协议,用于以抽象方式描述要交换的数据. 也就是说,为了进行通信,客户端和服务不必共享相同的类型,而只需共享相同的数据协定. 数据协定为每个参数或 ... 
- ln in Linux
			默认情况(硬连接) ln 目标 连接名称 ll -i 显示文件的inode信息,即文件节点信息 ➜ test1 ll -i 1.txt 27987655 -rw-r--r-- 1 myuser ... 
- mongod 安装
			mongod --logpath F:\mongo\db\logs\logs.log --logappend --dbpath F:\mongo\db\data --directoryperdb -- ... 
- Python基本编程题
			问题1:仅使用 Python 基本语法,即不使用任何模块,编写 Python 程序计算下列数学表达式的结果并输出,小数点后保留3位. ... 
- Ubuntu—安装python的第三方包gevent
			今晚花很多时间, 使用 sudo pip3 install gevent 但是始终没有成功. 柳暗花明又一村 sudo apt-get install python3-gevent 搞定!!! 人生如 ... 
- 多重共性和VIF检验
			图片来源https://wenku.baidu.com/view/7008df8383d049649b66581a.html 和 https://wenku.baidu.com/view/6acdf9 ... 
- 用 Python 编写的 Python 解释器
			Allison是Dropbox的工程师,在那里她维护着世界上最大的由Python客户组成的网络.在Dropbox之前,她是Recurse Center的引导师, … 她在北美的PyCon做过关于Pyt ... 
- loadrunner--基础2
			LR11-03 一.并发测试(n VU) 1.并发测试两个条件 1)脚本中要有 集合点(并发点) 2)控制台中要设置并发策略(选择第一项,所有虚拟用户到达集合点后释放) 集合点: 5个线程,代表5个V ... 
- Spring演示及总结
			一.目标 二.分工 三.回顾 发现问题: 第一个冲刺的任务以基本完成,但队友的状态相对有些疲软,主要原因可能是这两周有好几个课程大作业要赶, 有的队友还要为比赛做准备,及做一些其他是项目,时间较紧,有 ... 
- 学习调用第三方的WebService服务
			互联网上面有很多的免费webService服务,我们可以调用这些免费的WebService服务,将一些其他网站的内容信息集成到我们的应用中显示,下面就以查询国内手机号码归属地为例进行说明. 首先安利一 ... 
