zoukankan      html  css  js  c++  java
  • 【BZOJ3514】Codechef MARCH14 GERALD07加强版(LCT_主席树)

    题目:

    BZOJ3514

    分析:

    看到这题真的是一脸懵逼无从下手,只好膜题解。看到「森林的联通块数 = 点数 - 边数」这一句话就立刻什么都会了 QAQ 。

    这题最重要的就是意识到上面那个式子(正确性显然)。那么这个问题就变成了:([l,r]) 中最多选出多少条边,使得图中不存在环。根据 Kruskal 的原理,贪心地选就能保证选出的边最多,所以我们不妨假定尽量选编号较大的边。

    给每条边 (i)(nxt_i) ,表示从 (i) 开始向后依次插入边,插入到 (nxt_i) 这条边时会出现 包含 (i) 环(不存在则为无穷大)。即,如果 (i)(nxt_i) 同时可选,由于尽量选择标号大的边,所以选上 (nxt_i) 而把 (i) 删掉。(nxt_i) 也可理解为会「废掉」(i) 的第一条边。那么答案就是满足 (iin[l,r])(nxt[i] otin[l,r]) 的边数。这是一个二维数点问题,直接用主席树解决即可。

    如何 (O(n)) 求出 (nxt_i) 呢?考虑从小到大加边,当加入边 (i) 时,如果出现了环,那么断掉环上最小的边 (j) ,则 (nxt_j=i) 。这个过程用 LCT 维护。

    代码:

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cctype>
    using namespace std;
    
    namespace zyt
    {
    	template<typename T>
    	inline bool read(T &x)
    	{
    		char c;
    		bool f = false;
    		x = 0;
    		do
    			c = getchar();
    		while (c != EOF && c != '-' && !isdigit(c));
    		if (c == EOF)
    			return false;
    		if (c == '-')
    			f = true, c = getchar();
    		do
    			x = x * 10 + c - '0', c = getchar();
    		while (isdigit(c));
    		if (f)
    			x = -x;
    		return true;
    	}
    	template<typename T>
    	inline void write(T x)
    	{
    		static char buf[20];
    		char *pos = buf;
    		if (x < 0)
    			putchar('-'), x = -x;
    		do
    			*pos++ = x % 10 + '0';
    		while (x /= 10);
    		while (pos > buf)
    			putchar(*--pos);
    	}
    	const int N = 2e5 + 10, M = 2e5 + 10, B = 20, P = N + M, INF = 0x3f3f3f3f;
    	class Link_Cut_Tree
    	{
    	private:
    		struct nulltag {};
    		struct node
    		{
    			int val, min;
    			bool revtag;
    			node *fa, *s[2];
    			node(nulltag)
    				: val(INF), min(INF), revtag(false)
    			{
    				fa = s[0] = s[1] = this;
    			}
    			node(const int _val)
    				: val(_val), min(_val), revtag(false)
    			{
    				fa = s[0] = s[1] = null;
    			}
    		}*pos[P];
    		static node *null;
    		static void update(node *const rot)
    		{
    			rot->min = min(rot->val, min(rot->s[0]->min, rot->s[1]->min));
    		}
    		static void rev(node *const rot)
    		{
    			swap(rot->s[0], rot->s[1]), rot->revtag ^= 1;
    		}
    		static void pushdown(node *const rot)
    		{
    			if (rot->revtag)
    			{
    				if (rot->s[0] != null)
    					rev(rot->s[0]);
    				if (rot->s[1] != null)
    					rev(rot->s[1]);
    				rot->revtag = 0;
    			}
    		}
    		static void pushdown_all(node *const rot)
    		{
    			if (!isrot(rot))
    				pushdown_all(rot->fa);
    			pushdown(rot);
    		}
    		static bool isrot(const node *const rot)
    		{
    			return rot != rot->fa->s[0] && rot != rot->fa->s[1];
    		}
    		static bool dir(const node *const rot)
    		{
    			return rot == rot->fa->s[1];
    		}
    		static void rotate(node *const rot)
    		{
    			node *f = rot->fa, *ff = f->fa;
    			bool d = dir(rot);
    			if (!isrot(f))
    				ff->s[dir(f)] = rot;
    			rot->fa = ff;
    			f->s[d] = rot->s[!d];
    			if (rot->s[!d] != null)
    				rot->s[!d]->fa = f;
    			rot->s[!d] = f;
    			f->fa = rot;
    			update(f);
    		}
    		static void splay(node *const rot)
    		{
    			pushdown_all(rot);
    			while (!isrot(rot))
    			{
    				node *f = rot->fa;
    				if (isrot(f))
    					rotate(rot);
    				else if (dir(f) ^ dir(rot))
    					rotate(rot), rotate(rot);
    				else
    					rotate(f), rotate(rot);
    			}
    			update(rot);
    		}
    		static void access(node *rot)
    		{
    			for (node *last = null; rot != null; last = rot, rot = rot->fa)
    				splay(rot), rot->s[1] = last, update(rot);
    		}
    		static void mkrot(node *const rot)
    		{
    			access(rot), splay(rot), rev(rot);
    		}
    		static node *findrot(node *rot)
    		{
    			access(rot), splay(rot);
    			while (rot->s[0] != null)
    				rot = rot->s[0];
    			return rot;
    		}
    	public:
    		bool connect(const int x, const int y)
    		{
    			return findrot(pos[x]) == findrot(pos[y]);
    		}
    		void link(const int x, const int y)
    		{
    			node *rot1 = pos[x], *rot2 = pos[y];
    			mkrot(rot1), splay(rot1), rot1->fa = rot2;
    		}
    		void cut(const int x, const int y)
    		{
    			node *rot1 = pos[x], *rot2 = pos[y];
    			mkrot(rot1), access(rot2), splay(rot1);
    			rot1->s[1] = rot2->fa = null;
    			update(rot1);
    		}
    		int query(const int x, const int y)
    		{
    			node *rot1 = pos[x], *rot2 = pos[y];
    			mkrot(rot1), access(rot2), splay(rot1);
    			return rot1->min;
    		}
    		void init(const int n, const int *const w)
    		{
    			for (int i = 1; i <= n; i++)
    				pos[i] = new node(w[i]);
    		}
    
    	}lct;
    	typedef Link_Cut_Tree LCT;
    	LCT::node *LCT::null = new LCT::node(LCT::nulltag());
    	namespace Chairman_Tree
    	{
    		struct node
    		{
    			int sum, lt, rt;
    		}tree[M * B];
    		int cnt;
    		void add(int &rot, const int pre, const int lt, const int rt, const int pos, const int x)
    		{
    			rot = ++cnt;
    			tree[rot] = tree[pre];
    			tree[rot].sum += x;
    			if (lt == rt)
    				return;
    			int mid = (lt + rt) >> 1;
    			if (pos <= mid)
    				add(tree[rot].lt, tree[pre].lt, lt, mid, pos, x);
    			else
    				add(tree[rot].rt, tree[pre].rt, mid + 1, rt, pos, x);
    		}
    		int query(const int rot1, const int rot2, const int lt, const int rt, const int ls, const int rs)
    		{
    			if (!rot2 || (ls <= lt && rt <= rs))
    				return tree[rot2].sum - tree[rot1].sum;
    			int mid = (lt + rt) >> 1;
    			if (rs <= mid)
    				return query(tree[rot1].lt, tree[rot2].lt, lt, mid, ls, rs);
    			else if (ls > mid)
    				return query(tree[rot1].rt, tree[rot2].rt, mid + 1, rt, ls, rs);
    			else
    				return query(tree[rot1].lt, tree[rot2].lt, lt, mid, ls, rs)
    					+ query(tree[rot1].rt, tree[rot2].rt, mid + 1, rt, ls, rs);
    		}
    	}
    	typedef pair<int, int> pii;
    	int head[M], w[P], n, m, nxt[M];
    	pii arr[M];
    	int work()
    	{
    		using namespace Chairman_Tree;
    		int lastans = 0, q, type;
    		read(n), read(m), read(q), read(type);
    		for (int i = 1; i <= n; i++)
    			w[i] = INF;
    		for (int i = 1; i <= m; i++)
    			w[i + n] = i, nxt[i] = m + 1;
    		lct.init(n + m, w);
    		for (int i = 1; i <= m; i++)
    		{
    			int a, b;
    			read(a), read(b);
    			arr[i] = pii(a, b);
    			if (a == b)
    			{
    				nxt[i] = i;
    				continue;
    			}
    			if (lct.connect(a, b))
    			{
    				int tmp = lct.query(a, b);
    				nxt[tmp] = i;
    				lct.cut(tmp + n, arr[tmp].first);
    				lct.cut(tmp + n, arr[tmp].second);
    			}
    			lct.link(a, i + n), lct.link(i + n, b);
    		}
    		for (int i = 1; i <= m; i++)
    			add(head[i], head[i - 1], 1, m + 1, nxt[i], 1);
    		while (q--)
    		{
    			int l, r;
    			read(l), read(r);
    			if (type)
    				l ^= lastans, r ^= lastans;
    			write(lastans = (n - query(head[l - 1], head[r], 1, m + 1, r + 1, m + 1)));
    			putchar('
    ');
    		}
    		return 0;
    	}
    }
    int main()
    {
    	return zyt::work();
    }
    
  • 相关阅读:
    接口自动化测试中解决所遇问题的博客链接
    python中logging日志模块详解
    yaml.load()时总是出现警告:YAMLLoadWarning: calling yaml.load() without Loader=...
    基于ArcGIS Desktop 10.2开发的环境安装
    【部署】IIS导入证书后绑定报错“证书中的一个或多个中间证书丢失”
    IIS7.x 生成CSR证书请求文件
    Sql Server多种分页性能的比较
    网页上出现D盾拦截,删除、取消
    Fusioncharts图表常用参数设置
    Windows Server 2016 安装.NET Framework 3.5 错误
  • 原文地址:https://www.cnblogs.com/zyt1253679098/p/10881859.html
Copyright © 2011-2022 走看看