zoukankan      html  css  js  c++  java
  • [BZOJ3514]Codechef MARCH14 GERALD07加强版

    [BZOJ3514]Codechef MARCH14 GERALD07加强版

    试题描述

    N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。

    输入

    第一行四个整数N、M、K、type,代表点数、边数、询问数以及询问是否加密。
    接下来M行,代表图中的每条边。
    接下来K行,每行两个整数L、R代表一组询问。对于type=0的测试点,读入的L和R即为询问的L、R;对于type=1的测试点,每组询问的L、R应为L xor lastans和R xor lastans。

    输出

    K行每行一个整数代表该组询问的联通块个数。

    输入示例

    3 5 4 0
    1 3
    1 2
    2 1
    3 2
    2 2
    2 3
    1 5
    5 5
    1 2

    输出示例

    2
    1
    3
    1

    数据规模及约定

    对于100%的数据,1≤N、M、K≤200,000。

    题解

    对于每一条边,我们用 LCT 维护时间最大生成树(即如果加进来一条边成环,那么把最早加进来的边删除)。这样对于每一条边我们可以处理出它在什么时候能够“发挥作用”,意思就是加入这条边后会使得全局连通块减小 1,我们不妨令 pre[i] 表示第 i 条边在 pre[i] 时刻之后能够发挥作用,那么一个询问 [l, r] 就是询问 [l, r] 区间中 pre 数组中小于 l 的数有多少个,主席树即可。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 200010
    #define maxm 200010
    #define maxnode 500010
    #define oo 2147483647
    
    struct Node {
    	int val, mnv;
    	bool rev;
    	Node(): rev(0) {}
    	Node(int _): val(_) {}
    } ns[maxnode];
    int fa[maxnode], ch[maxnode][2], S[maxn], top;
    bool isrt(int u) { return !fa[u] || (ch[fa[u]][0] != u && ch[fa[u]][1] != u); }
    void maintain(int o) {
    	ns[o].mnv = ns[o].val;
    	for(int i = 0; i < 2; i++) if(ch[o][i])
    		ns[o].mnv = min(ns[o].mnv, ns[ch[o][i]].mnv);
    	return ;
    }
    void pushdown(int o) {
    	if(!ns[o].rev) return ;
    	swap(ch[o][0], ch[o][1]);
    	for(int i = 0; i < 2; i++) if(ch[o][i])
    		ns[ch[o][i]].rev ^= 1;
    	ns[o].rev = 0;
    	return ;
    }
    void rotate(int u) {
    	int y = fa[u], z = fa[y], l = 0, r = 1;
    	if(!isrt(y)) ch[z][ch[z][1]==y] = u;
    	if(ch[y][1] == u) swap(l, r);
    	fa[u] = z; fa[y] = u; fa[ch[u][r]] = y;
    	ch[y][l] = ch[u][r]; ch[u][r] = y;
    	maintain(y); maintain(u);
    	return ;
    }
    void splay(int u) {
    	int t = u; S[top = 1] = t;
    	while(!isrt(t)) S[++top] = fa[t], t = fa[t];
    	while(top) pushdown(S[top--]);
    	while(!isrt(u)) {
    		int y = fa[u], z = fa[y];
    		if(!isrt(y)) {
    			if(ch[y][0] == u ^ ch[z][0] == y) rotate(u);
    			else rotate(y);
    		}
    		rotate(u);
    	}
    	return ;
    }
    void access(int u) {
    	splay(u); ch[u][1] = 0; maintain(u);
    	while(fa[u]) splay(fa[u]), ch[fa[u]][1] = u, maintain(fa[u]), splay(u);
    	return ;
    }
    void makeroot(int u) {
    	access(u); ns[u].rev ^= 1;
    	return ;
    }
    void link(int a, int b) {
    	makeroot(b); fa[b] = a;
    	return ;
    }
    void cut(int a, int b) {
    	makeroot(a); access(b); ch[b][0] = fa[a] = 0; maintain(b);
    	return ;
    }
    int _mnv;
    void query(int a, int b) {
    	makeroot(a); access(b); _mnv = ns[b].mnv;
    	return ;
    }
    
    struct Edge {
    	int u, v;
    	Edge() {}
    	Edge(int _, int __): u(_), v(__) {}
    } es[maxm];
    
    int pa[maxn];
    int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); }
    
    #define maxNode 14400010
    int pre[maxm], rt[maxm];
    int ToT, sumv[maxNode], lc[maxNode], rc[maxNode];
    void update(int& y, int x, int l, int r, int p) {
    	sumv[y = ++ToT] = sumv[x] + 1;
    	if(l == r) return ;
    	int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
    	if(p <= mid) update(lc[y], lc[x], l, mid, p);
    	else update(rc[y], rc[x], mid + 1, r, p);
    	return ;
    }
    int query(int o, int l, int r, int qr) {
    	if(!o) return 0;
    	if(r <= qr) return sumv[o];
    	int mid = l + r >> 1, ans = query(lc[o], l, mid, qr);
    	if(qr > mid) ans += query(rc[o], mid + 1, r, qr);
    	return ans;
    }
    
    int main() {
    	int n = read(), m = read(), q = read(), tp = read();
    	for(int i = 1; i <= n; i++) ns[i] = Node(oo), maintain(i), pa[i] = i;
    	for(int i = 1; i <= m; i++) {
    		int u = read(), v = read();
    		if(u == v){ pre[i] = i; continue; }
    		es[i] = Edge(u, v);
    		ns[i+n] = Node(i); maintain(i + n);
    		int U = findset(u), V = findset(v);
    		if(U == V) {
    			query(u, v);
    			pre[i] = _mnv;
    			cut(es[_mnv].u, _mnv + n); cut(_mnv + n, es[_mnv].v);
    			link(u, i + n); link(i + n, v);
    		}
    		else {
    			pa[V] = U;
    			pre[i] = 0;
    			link(u, i + n); link(i + n, v);
    		}
    	}
    	
    	for(int i = 1; i <= m; i++) update(rt[i], rt[i-1], 0, m, pre[i]);
    	int lst = 0;
    	while(q--) {
    		int l = read() ^ lst * tp, r = read() ^ lst * tp;
    		printf("%d
    ", lst = n - (query(rt[r], 0, m, l - 1) - query(rt[l-1], 0, m, l - 1)));
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    js命名空间
    window安装node.js
    JS添加可信站点、修改ActiveX安全设置,禁用弹出窗口阻止程序的方法
    Javascript 操作select控件大全(新增、修改、删除、选中、清空、判断存在等)
    DIV+CSS两种盒子模型
    table中的tbody标签
    兼容获取元素的样式属性值
    Arch linux 使用心得
    763. 划分字母区间
    <Leetcode>93. 复原地址
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6688681.html
Copyright © 2011-2022 走看看