省队集训 Day7 选点游戏
【题目大意】
维护一个$n$个点的图,$m$个操作,支持两个操作:
1. 连接$(u, v)$这条边;
2. 询问$u$所在的联通块中,能选出的最大合法的点数。
一个方案是合法的,当且仅当对于所有被选择的点,他们都没有直接通过一条边相连。
$n \leq 2*10^5, m\leq 8*10^5$
【题解】
考虑用LCT来维护这个图。
对于实边的Splay,维护$h_it_j$,其中$i, j \in \{0, 1\}$,表示前面选择$i$,后面选择$j$。(选0表示不选,选1表示选)
这个是可以合并信息的。
考虑虚边,对于每个虚边连到的实边的点,维护$l_i$,其中$i \in \{0,1\}$,分别表示$l_i$必须为0,以及$l_i$可以为0的值。
那么$l_i$可以通过连的虚边的值转移来。
那么连到的实边的点的val就可以用$l_i$表示。
在access的时候和link的时候(link可以用两个makeroot来做)支持实边虚边转换即可。
# include <stdio.h>
# include <assert.h>
# include <iostream>
# include <string.h>
# include <algorithm> using namespace std; typedef long long ll;
typedef unsigned long long ull;
typedef long double ld; inline int getint() {
int x = ; char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = (x<<) + (x<<) + ch - '', ch = getchar();
return x;
} const int N = 2e5 + , M = 5e5 + , inf = 1e9; int n, m; struct node {
int h0t0, h0t1, h1t0, h1t1;
node () {}
node (int h0t0, int h0t1, int h1t0, int h1t1) : h0t0(h0t0), h0t1(h0t1), h1t0(h1t0), h1t1(h1t1) {}
inline friend node operator + (node a, node b) {
// a tail with b head
node p;
p.h0t0 = max(a.h0t1 + b.h0t0, a.h0t0 + max(b.h1t0, b.h0t0));
p.h0t1 = max(a.h0t1 + b.h0t1, a.h0t0 + max(b.h1t1, b.h0t1));
p.h1t0 = max(a.h1t1 + b.h0t0, a.h1t0 + max(b.h1t0, b.h0t0));
p.h1t1 = max(a.h1t1 + b.h0t1, a.h1t0 + max(b.h1t1, b.h0t1));
return p;
}
inline int gans() {
return max(max(h0t0, h0t1), max(h1t0, h1t1));
}
inline void prt() {
printf("{%d %d %d %d}", h0t0, h0t1 == -inf ? - : h0t1, h1t0 == -inf ? - : h1t0, h1t1);
}
}; struct LCT {
node p[N], val[N]; int l0[N], l1[N];
int ch[N][], fa[N];
bool rev[N]; # define ls ch[x][]
# define rs ch[x][] inline void up(int x) {
if(!x) return ;
// ...
p[x] = val[x];
if(ls) p[x] = p[ls] + p[x];
if(rs) p[x] = p[x] + p[rs];
} inline void pushrev(int x) {
if(!x) return ;
swap(ch[x][], ch[x][]);
// ...
swap(p[x].h1t0, p[x].h0t1);
rev[x] ^= ;
} inline void down(int x) {
if(!x) return ;
if(rev[x]) {
pushrev(ls);
pushrev(rs);
rev[x] ^= ;
}
} # undef ls
# undef rs inline bool isrt(int x) {
return ch[fa[x]][] != x && ch[fa[x]][] != x;
} inline void rotate(int x) {
int y = fa[x], z = fa[y], ls = ch[y][] == x, rs = ls ^ ;
if(!isrt(y)) ch[z][ch[z][] == y] = x;
fa[ch[x][rs]] = y, fa[y] = x, fa[x] = z;
ch[y][ls] = ch[x][rs]; ch[x][rs] = y;
up(y); up(x);
} int st[N];
inline void splay(int x) {
int stn = , tx = x;
while(!isrt(tx)) st[++stn] = tx, tx = fa[tx];
st[++stn] = tx;
for (int i=stn; i; --i) down(st[i]);
while(!isrt(x)) {
int y = fa[x], z = fa[y];
if(!isrt(y)) {
if((ch[z][] == y) ^ (ch[y][] == x)) rotate(x);
else rotate(y);
}
rotate(x);
}
} inline void del(int y, int x) {
int p0 = max(p[x].h0t0, p[x].h0t1), p1 = max(p[x].h1t0, p[x].h1t1);
l0[y] += p0;
l1[y] += max(p0, p1);
}
inline void ins(int y, int x) {
int p0 = max(p[x].h0t0, p[x].h0t1), p1 = max(p[x].h1t0, p[x].h1t1);
l0[y] -= p0;
l1[y] -= max(p0, p1);
} inline int access(int x) {
int t = ;
for (; x; t = x, x = fa[x]) {
splay(x);
// ...
if(ch[x][]) del(x, ch[x][]);
if(t) ins(x, t);
val[x].h0t0 = l1[x];
val[x].h1t1 = l0[x] + ;
ch[x][] = t;
up(x);
}
return t;
} inline void makeroot(int x) {
access(x); splay(x); pushrev(x);
} inline void link(int x, int y) {
makeroot(x); makeroot(y);
fa[x] = y;
// ...
int p0 = max(p[x].h0t0, p[x].h0t1), p1 = max(p[x].h1t0, p[x].h1t1);
l0[y] += p0;
l1[y] += max(p0, p1);
val[y].h0t0 = l1[y];
val[y].h1t1 = l0[y] + ;
up(y);
} inline void debug() {
for (int x=; x<=n; ++x) {
printf("x = %d,fa = %d,ls = %d,rs = %d, p = ", x, fa[x], ch[x][], ch[x][]);
p[x].prt();
printf(", val = ");
val[x].prt();
printf(", l0 = %d,l1 = %d\n", l0[x], l1[x]);
}
}
}T; int main() {
freopen("game.in", "r", stdin);
freopen("game.out", "w", stdout);
n = getint();
for (int x=; x<=n; ++x) {
T.val[x] = T.p[x] = node(, -inf, -inf, );
T.ch[x][] = T.ch[x][] = T.fa[x] = ; T.rev[x] = ;
T.l0[x] = T.l1[x] = ;
}
register int Q = getint(), op, u, v;
while(Q--) {
// T.debug();
op = getint(), u = getint();
if(op == ) {
T.makeroot(u);
printf("%d\n", T.p[u].gans());
// cout << ... << endl;
} else {
v = getint();
T.link(u, v);
}
}
return ;
}
省队集训 Day7 选点游戏的更多相关文章
- HN2018省队集训
HN2018省队集训 Day1 今天的题目来自于雅礼的高二学长\(dy0607\). 压缩包下载 密码: 27n7 流水账 震惊!穿着该校校服竟然在四大名校畅通无阻?霸主地位已定? \(7:10\)从 ...
- JS省队集训记
不知不觉省队集训已经结束,离noi也越来越近了呢 论考前实战训练的重要性,让我随便总结一下这几天的考试 Day 1 T1 唉,感觉跟xj测试很像啊?meet in middle,不过这种题不多测是什么 ...
- 「2017 山东三轮集训 Day7 解题报告
「2017 山东三轮集训 Day7」Easy 练习一下动态点分 每个点开一个线段树维护子树到它的距离 然后随便查询一下就可以了 注意线段树开大点... Code: #include <cstdi ...
- [2018HN省队集训D9T1] circle
[2018HN省队集训D9T1] circle 题意 给定一个 \(n\) 个点的竞赛图并在其中钦定了 \(k\) 个点, 数据保证删去钦定的 \(k\) 个点后这个图没有环. 问在不删去钦定的这 \ ...
- 【LOJ6077】「2017 山东一轮集训 Day7」逆序对 生成函数+组合数+DP
[LOJ6077]「2017 山东一轮集训 Day7」逆序对 题目描述 给定 n,k ,请求出长度为 n的逆序对数恰好为 k 的排列的个数.答案对 109+7 取模. 对于一个长度为 n 的排列 p ...
- [2018HN省队集训D8T1] 杀毒软件
[2018HN省队集训D8T1] 杀毒软件 题意 给定一个 \(m\) 个01串的字典以及一个长度为 \(n\) 的 01? 序列. 对这个序列进行 \(q\) 次操作, 修改某个位置的字符情况以及查 ...
- [2018HN省队集训D8T3] 水果拼盘
[2018HN省队集训D8T3] 水果拼盘 题意 给定 \(n\) 个集合, 每个集合包含 \([1,m]\) 中的一些整数, 在这些集合中随机选取 \(k\) 个集合, 求这 \(k\) 个集合的并 ...
- [2018HN省队集训D6T2] girls
[2018HN省队集训D6T2] girls 题意 给定一张 \(n\) 个点 \(m\) 条边的无向图, 求选三个不同结点并使它们两两不邻接的所有方案的权值和 \(\bmod 2^{64}\) 的值 ...
- [Luogu P4143] 采集矿石 [2018HN省队集训D5T3] 望乡台platform
[Luogu P4143] 采集矿石 [2018HN省队集训D5T3] 望乡台platform 题意 给定一个小写字母构成的字符串, 每个字符有一个非负权值. 输出所有满足权值和等于这个子串在所有本质 ...
随机推荐
- TensorFlow源码框架 杂记
一.为什么我们需要使用线程池技术(ThreadPool) 线程:采用“即时创建,即时销毁”策略,即接受请求后,创建一个新的线程,执行任务,完毕后,线程退出: 线程池:应用软件启动后,立即创建一定数量的 ...
- UVALive - 6869 Repeated Substrings 后缀数组
题目链接: http://acm.hust.edu.cn/vjudge/problem/113725 Repeated Substrings Time Limit: 3000MS 样例 sample ...
- 从零讲JAVA ,给你一条 清晰地学习道路!该学什么就学什么!!
1.计算机基础: 1.1数据机构基础: 主要学习:1.向量,链表,栈,队列和堆,词典.熟悉2.树,二叉搜索树.熟悉3.图,有向图,无向图,基本概念4.二叉搜索A,B,C类熟练,9大排序熟悉.5.树的前 ...
- iOS- Exception异常处理
1.Exception 前言 在iOS里对异常的处理及捕获,并没有其它语言里那么常见,相信很多iOS程序员都知道,更多的时候是对内存的的检测与分析,检测相关内存方面的问题. 而在app闪退并不是因为内 ...
- TCP系列22—重传—12、Forward Retransmit
一.概述 forward retransmit相关的内容在RFC6675中有描述,可以参考RFC6675 section 4中NextSeg ()的定义.forward retransmit中文名可以 ...
- Unsupported major.minor version 52.
面试的时候,京东和美团,360的面试官都问到了同一个问题,java1.7与java1.8的区别, 于是想做个小小的例子: 我的eclipse刚开始是1.7的,后来,我把环境改成了1.8的, 方法:右击 ...
- 累积下学习 C#时和 Java时的不同点
==和equals()方法的区别: 首先有一个观点: 这两个都是用来比较值是否相等的 ( 这里的值有时候指的是地址值, 有时候是存储的值; 下面将地址值称为地址, 存储的值称为值 ) 在Java中: ...
- WPF值转换实例
WPF绑定功能非常方便,有时候点击某值时在另t一处显示此值的另一表现形式或调用其对应的其它值,用WPF值转换功能会很方便,下面就一LISTBOX和TEXTBLOCK控件,把LISTBOX中的值转换成除 ...
- BZOJ 1491 社交网络(最短路)
对于这道题,如果我们能求出s到t的最短路径数目和s由v到t的最短路径数目,剩下的很好求了. 令dis[i][j]表示i到j的最短路径,dp[i][j]表示i到j的最短路径条数,如果dis[s][v]+ ...
- Python re(正则表达式)模块
python正则表达式 正则表达式是一个特殊的字符序列,它能帮助我们方便的检查一个字符串是否与某种模式匹配.Python自1.5版本起增加了re模块,它提供Perl风格的正则表达式模式.re模块使Py ...