zoukankan      html  css  js  c++  java
  • [IOI2018] werewolf 狼人

    \(\text{Problem}\)

    大概就是给张图 \(n \le 200000,m \le 400000\),点权为编号本身
    \(q\) 个询问,能否在 \(S\)\(E\) 的路径上找到一个点 \(X\) 使得 \(S\)\(X\) 所有点权大于等于 \(L\)\(X\)\(E\) 所有点权小于等于 \(R\)

    \(\text{Solution}\)

    不难想到对于 \(L\) 的限制弄一棵边权为相邻点的最小权值的最大生成树来,对 \(R\) 则是最小生成树
    然后考虑在这条路径上 \(S\) 出发最远能走多远,\(E\) 出发最远能走多远,两者有交集则可行
    因为两棵生成树形态显然不一样,而且很多判交集
    考虑 \(Kruskal\) 重构树的性质
    那么它走最远到的节点的子树中的叶子节点就是它在原图中能走过的点
    询问变为判断在第一棵 \(Kruskal\) 重构树中覆盖的点和第二棵覆盖的点有没有交集
    考虑两棵树各自的 \(dfs\) 序,给原图中的点记下
    然后变成二维偏序问题
    在线主席树,离线树状数组即可

    传统题形式

    \(\text{Code}\)

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #define RE register
    #define IN inline
    using namespace std;
    
    const int N = 4e5 + 5;
    int n, m, q, Up, cnt, ans[N];
    struct node{int x, y;}E[N], a[N];
    struct Que{int s, t, l, r, f;}Q[N], b[N];
    IN bool cmpQue(Que a, Que b){return (a.t < b.t) ? 1 : (a.t == b.t ? a.f > b.f : 0);}
    struct nod{int x, y, z;}p[N];
    IN bool cmpMin(nod a, nod b){return a.z < b.z;}
    IN bool cmpMax(nod a, nod b){return a.z > b.z;}
    
    IN void read(int &x)
    {
    	x = 0; char ch = getchar();
    	for(; !isdigit(ch); ch = getchar());
    	for(; isdigit(ch); x = (x<<3)+(x<<1)+(ch^48), ch = getchar());
    }
    
    struct UnionSet{
    	int fa[N];
    	IN void Set(){for(RE int i = 1; i <= n * 2; i++) fa[i] = i;}
    	int Find(int x){return (fa[x] == x ? x : fa[x] = Find(fa[x]));}
    }S;
    
    struct KruskalTree{
    	int h[N], tot, dfn[N], dfc, siz[N], f[N][20], val[N], Tot;
    	struct edge{int to, nxt;}e[N << 1];
    	IN void add(int x, int y){e[++tot] = edge{y, h[x]}, h[x] = tot;}
    	IN void Kruskal(int ty)
    	{
    		for(RE int i = 1; i <= m; i++)
    		{
    			p[i].x = E[i].x, p[i].y = E[i].y;
    			if (ty == 1) p[i].z = min(p[i].x, p[i].y);
    			else p[i].z = max(p[i].x, p[i].y);
    		}
    		if (ty == 1) sort(p + 1, p + m + 1, cmpMax);
    		else sort(p + 1, p + m + 1, cmpMin);
    		S.Set(); int s = 0;
    		for(RE int i = 1; i <= n; i++) val[++Tot] = i;
    		for(RE int i = 1, x, y; i <= m; i++)
    		{
    			if ((x = S.Find(p[i].x)) == (y = S.Find(p[i].y))) continue;
    			val[++Tot] = p[i].z, add(Tot, x), add(Tot, y), S.fa[x] = S.fa[y] = Tot, ++s;
    			if (s == n - 1) break;
    		}
    	}
    	IN void Dfs(int x)
    	{
    		for(RE int i = 1; i <= 19; i++)
    			if (f[x][i - 1]) f[x][i] = f[f[x][i - 1]][i - 1];
    			else break;
    		dfn[x] = ++dfc, siz[x] = 1;
    		for(RE int i = h[x]; i; i = e[i].nxt)
    			f[e[i].to][0] = x, Dfs(e[i].to), siz[x] += siz[e[i].to];
    	}
    	IN void TagDFN(int ty)
    	{
    		Dfs(Tot), Up = max(Up, dfc);
    		for(RE int i = 1; i <= n; i++)
    			if (ty == 1) a[i].x = dfn[i]; else a[i].y = dfn[i];
    	}
    	IN int Find(int ty, int x, int v)
    	{
    		for(RE int i = 19; i >= 0; i--)
    		if (f[x][i])
    			if (ty == 1 && val[f[x][i]] >= v) x = f[x][i];
    			else if (ty == 2 && val[f[x][i]] <= v) x = f[x][i];
    		return x;
    	}
    }T1, T2;
    
    struct BIT{
    	int c[N];
    	IN int lowbit(int x){return x & (-x);}
    	IN void Add(int x){for(; x <= Up; x += lowbit(x)) ++c[x];}
    	IN int Query(int x){int s = 0; for(; x; x -= lowbit(x)) s += c[x]; return s;}
    }T;
    
    int main()
    {
    	read(n), read(m), read(q);
    	for(RE int i = 1; i <= m; i++) read(E[i].x), read(E[i].y), ++E[i].x, ++E[i].y;
    	T1.Kruskal(1), T1.TagDFN(1), T2.Kruskal(2), T2.TagDFN(2);
    	for(RE int i = 1; i <= n; i++) b[++cnt] = Que{0, a[i].x, a[i].y, 0, 2};
    	for(RE int i = 1; i <= q; i++) read(Q[i].s), read(Q[i].t), read(Q[i].l), read(Q[i].r);
    	for(RE int i = 1, x, y; i <= q; i++)
    	{
    		++Q[i].s, ++Q[i].t, ++Q[i].l, ++Q[i].r;
    		x = T1.Find(1, Q[i].s, Q[i].l), y = T2.Find(2, Q[i].t, Q[i].r);
    		b[++cnt] = Que{i, T1.dfn[x] - 1, T2.dfn[y], T2.dfn[y] + T2.siz[y] - 1, -1};
    		b[++cnt] = Que{i, T1.dfn[x] + T1.siz[x] - 1, T2.dfn[y], T2.dfn[y] + T2.siz[y] - 1, 1};
    	}
    	sort(b + 1, b + cnt + 1, cmpQue);
    	for(RE int i = 1; i <= cnt; i++)
    		if (b[i].f == 2) T.Add(b[i].l);
    		else ans[b[i].s] += (T.Query(b[i].r) - T.Query(b[i].l - 1)) * b[i].f;
    	for(RE int i = 1; i <= q; i++) printf("%d\n", (ans[i] > 0));
    }
    
  • 相关阅读:
    Cheap Kangaroo(求多个数的最大公约数)
    poj 1094 Sorting It All Out(拓扑排序)
    hdu 5695 Gym Class(拓扑排序)
    Cyclic Components (并查集)
    GCD LCM
    And Then There Was One (约瑟夫环变形)
    System Overload(约瑟夫环变形)
    POJ-1639 Picnic Planning 度数限制最小生成树
    Educational Codeforces Round 60 (Rated for Div. 2) E. Decypher the String
    (ACM模板)二分查找
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/15685387.html
Copyright © 2011-2022 走看看