【 bzoj 3514 】Codechef MARCH14 GERALD07加强版 - LCT
2016-01-21 16:48
459 查看
题意简单明了。。。
考虑从头开始加边。如果还是一棵树的时候,加入了一条边会怎么样。
如果还是树就不鸟他。
但是如果构成了环,那么这个环要存在的必要条件显然是最早的边要存在。(当然这个环上的其他边也要存在,但这不重要,因为如果最早的边存在了,这些边肯定会存在),如果将当前边设为EjE_j,这个环上标号最小的边设为EiE_i,那我们称EjE_j依赖于EiE_i。因为如果当前是棵树的情况下,如果EiE_i不在里面,即使EjE_j加入了也对树结构没有影响。因我们可以得到一个算法,按顺序加边,如果加入边(u,v)(u,v)后出现了环,那么就查询u→vu\rightarrow v的路径上标号最小的边,并把它删掉,将当前边的权值设为它,然后再加入当前边。区间[l,r][l,r]内的答案就是n-“区间内权值小于l的数的个数”。
于是前面的预处理可以拆边用LCT做,后面的查询用可持久化线段树。时间复杂度O(nlogn)O(n\log n),在线,常数略大。
离线的话大概是倒序维护标号最大生成树就可以了吧。
考虑从头开始加边。如果还是一棵树的时候,加入了一条边会怎么样。
如果还是树就不鸟他。
但是如果构成了环,那么这个环要存在的必要条件显然是最早的边要存在。(当然这个环上的其他边也要存在,但这不重要,因为如果最早的边存在了,这些边肯定会存在),如果将当前边设为EjE_j,这个环上标号最小的边设为EiE_i,那我们称EjE_j依赖于EiE_i。因为如果当前是棵树的情况下,如果EiE_i不在里面,即使EjE_j加入了也对树结构没有影响。因我们可以得到一个算法,按顺序加边,如果加入边(u,v)(u,v)后出现了环,那么就查询u→vu\rightarrow v的路径上标号最小的边,并把它删掉,将当前边的权值设为它,然后再加入当前边。区间[l,r][l,r]内的答案就是n-“区间内权值小于l的数的个数”。
于是前面的预处理可以拆边用LCT做,后面的查询用可持久化线段树。时间复杂度O(nlogn)O(n\log n),在线,常数略大。
离线的话大概是倒序维护标号最大生成树就可以了吧。
[code]#include <bits/stdc++.h> #define rep(i,a,b) for(int i = a , _ = b ; i <= _ ; i ++) #define per(i,a,b) for(int i = a , _ = b ; i >= _ ; i --) #define cr(x) memset(x , 0 , sizeof x) #define lc ch[u][0] #define rc ch[u][1] #define maxn 200007 #define maxm 400007 #define maxs 4000007 inline int rd() { char c = getchar(); while (!isdigit(c)) c = getchar() ; int x = c - '0'; while (isdigit(c = getchar())) x = x * 10 + c - '0'; return x; } inline void upmin(int&a , int b) { if (a > b) a = b; } typedef int arr[maxn]; typedef int lct[maxm]; typedef int seg[maxs]; const int inf = 0x7fffffff; arr x , y , pre , rt; lct val , rv , mn , fa , sta; int ch[maxm][2]; int n , m , q , tot , top , Type; void input() { n = rd() , m = rd() , q = rd() , Type = rd(); rep (i , 1 , m) x[i] = rd() , y[i] = rd(); } inline bool isrt(int u) { return (ch[fa[u]][0] != u) && (ch[fa[u]][1] != u); } inline void rev(int u) { if (!u) return; std::swap(lc , rc); rv[u] ^= 1; } inline void mt(int u) { if (!u) return; mn[u] = val[u]; if (lc) upmin(mn[u] , mn[lc]); if (rc) upmin(mn[u] , mn[rc]); } inline void ps(int u) { if (!u || !rv[u]) return; rev(lc) , rev(rc); rv[u] = 0; } inline void clear(int u) { for (sta[top ++] = u;u;u = fa[u]) sta[top ++] = fa[u]; for (;top;) ps(sta[-- top]); } inline void rot(int u) { int f = fa[u] , g = fa[f]; int l = (ch[f][1] == u) , r = l ^ 1; if (!isrt(f)) ch[g][ch[g][1] == f] = u; fa[u] = g , fa[f] = u; if (ch[u][r]) fa[ch[u][r]] = f; ch[f][l] = ch[u][r] , ch[u][r] = f; mt(f) , mt(u); } inline void splay(int u) { for (clear(u);!isrt(u);rot(u)) { int f = fa[u] , g = fa[f]; if (!isrt(f)) rot(((ch[f][1] == u) ^ (ch[g][1] == f)) ? u : f); } mt(u); } inline void access(int u) { int v = u; for (int t = 0;u;t = u , u = fa[u]) splay(u) , rc = t; splay(v); } inline void mkrt(int u) { access(u); rev(u); } inline void cut(int u , int v) { mkrt(v) , access(u); fa[lc] = 0 , lc = 0; mt(u); } inline void link(int u , int v) { mkrt(u) , fa[u] = v; access(u); } inline bool connected(int u , int v) { mkrt(v) , access(u); while (lc) u = lc; if (u != v) return 0; return 1; } inline int GetMin(int u , int v) { mkrt(v) , access(u); return mn[u]; } #undef lc #undef rc seg lc , rc , sz; void update(int pr , int&nr , int l , int r , int p) { if (!nr) nr = ++ tot; sz[nr] = sz[pr] + 1; if (l == r) return; int m = l + r >> 1; if (p <= m) rc[nr] = rc[pr] , update(lc[pr] , lc[nr] , l , m , p); else lc[nr] = lc[pr] , update(rc[pr] , rc[nr] , m + 1 , r , p); } int query(int pr , int nr , int l , int r , int p) { if (r <= p) return sz[nr] - sz[pr]; if (l > p) return 0; int m = l + r >> 1; int ret = query(lc[pr] , lc[nr] , l , m , p); if (p > m) ret += query(rc[pr] , rc[nr] , m + 1 , r , p); return ret; } void init() { rep (i , 1 , n) val[i] = mn[i] = inf; rep (i , 1 , m) { val[i + n] = mn[i + n] = i; int u = x[i] , v = y[i]; if (u == v) { pre[i] = -1; continue; } if (connected(u , v)) { int w = GetMin(u , v); cut(x[w] , w + n); cut(w + n , y[w]); pre[i] = w; } link(u , i + n); link(i + n , v); } rep (i , 1 , m) update(rt[i - 1] , rt[i] , 0 , m , pre[i] == -1 ? m : pre[i]); } void solve() { init(); int ans = 0; rep (i , 1 , q) { int l = rd() , r = rd(); if (Type) l ^= ans , r ^= ans; ans = query(rt[l - 1] , rt[r] , 0 , m , l - 1); printf("%d\n" , ans = n - ans); } } int main() { #ifndef ONLINE_JUDGE freopen("data.txt" , "r" , stdin); freopen("data.out" , "w" , stdout); #endif input(); solve(); return 0; }
相关文章推荐
- Redis HyperLogLog
- 从零开始配置Jenkins(三)——用户权限管理
- iOS游戏开发游戏功能之外的东西
- Object.defineProperties——MEAN开发后台的Model层
- 矩形覆盖
- HDU 2222 Keywords Search(AC自己主动机)
- Eclipse源代码分析
- MySQL 主从复制的原理和配置
- Ubuntu 查看系统驱动程序
- JQuery获取checkBox是否选中
- mac 终端 常用命令
- HBase
- Windows 窗体启动和关闭的事件顺序
- 关于Objective-C的内存管理小结
- PHP扩展开发(2) - VS2013环境搭建
- opencv数据结构-MAT结构详解
- http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx
- SSIS 关于并发的两个设置
- 进击的Android之ListView
- 11gR2 RAC时间同异常导致节点down掉问题处理