• Codeforces 1083C Max Mex


    Description

    一棵(N)个节点的树, 每个节点上都有 互不相同的 ([0, ~N-1]) 的数。

    定义一条路径上的数的集合为 (S), 求一条路径使得 (Mex(S)) 最大。

    带修改, (M) 次查询

    Solution

    用一棵权值线段树维护。

    节点 ([L,R])存储信息:是否有一条路径包含 ([L,R]) 内的所有数 以及 路径两个端点。

    合并两个区间: 在(4)个点中 枚举新路径的端点, 然后判断另外两个点是否在路径上即可。

    正解能 (O(1)) 合并, 然而这个解法需要(O(logN))

    所以总复杂度为 (O(Nlog^2N))

    Code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #define up(a, b) (a = a > b ? a : b)
    #define down(a, b) (a = a > b ? b : a)
    #define cmax(a, b) (a > b ? a : b)
    #define cmin(a, b) (a > b ? b : a)
    #define Abs(a) ((a) > 0 ? (a) : -(a))
    #define rd read()
    #define db double
    #define LL long long
    using namespace std;
    typedef pair<int, int> P;
    
    inline char nc(){
        static char buf[1<<14],*p1=buf,*p2=buf;
        return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read(){
        char c=nc();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=nc();}
        while(c>='0'&&c<='9'){x=x*10+c-'0',c=nc();}
        return x*f;
    }
    const int N = 2e5 + 5;
    
    int n, m, a[N], b[N], f[N][20], dep[N];
    int timer, tin[N], tout[N];
    
    vector<int> to[N];
    
    void dfs(int u) {
    	tin[u] = ++timer; // dfs序
    	for (int i = 0, up = to[u].size(); i < up; ++i) {
    		int nt = to[u][i];
    		if (nt == f[u][0])
    			continue;
    		dep[nt] = dep[u] + 1;
    		dfs(nt);
    	}
    	tout[u] = timer;
    }
    
    inline bool isanc(int u, int v) { // 判断u是否是v的祖先
    	return tin[u] <= tin[v] && tout[u] >= tout[v];
    }
    
    int getlca(int u, int v) {
    	if (isanc(u, v))
    		return u;
    	for (int i = 19; ~i; --i)
    		if (f[u][i] && (!isanc(f[u][i], v)))
    			u = f[u][i];
    	return f[u][0];
    }
    
    inline bool isondownpath(int u, P v) { //判断u是否是 竖直路径v() 上的点
    	return isanc(v.first, u) && isanc(u, v.second);
    }
    
    inline bool isonpath(int u, P v) { //判断u是否是 路径v()上的点
    	int lca = getlca(v.first, v.second);
    	return isondownpath(u, P(lca, v.second)) || isondownpath(u, P(lca, v.first));
    }
    
    P merge(P u, P v) { //合并两条路径
    	if (u.first == -1 || v.first == -1)
    		return P(-1, -1);
    	int g[4] = {u.first, u.second, v.first, v.second};
    	for (int i = 0; i < 4; ++i) {
    		for (int j = i + 1; j < 4; ++j) {
    			bool flag = true;
    			for (int k = 0; k < 4; ++k) {
    				if (k != i && k != j && !isonpath(g[k], P(g[i], g[j])))
    					flag = false;
    			}
    			if (flag)
    				return P(g[i], g[j]);
    		}
    
    	}
    	return P(-1, -1);
    }
    
    namespace SegT {
    	#define mid ((l + r) >> 1)
    	#define lson u << 1
    	#define rson u << 1 | 1
    	P t[N << 2];
    
    	void build(int l, int r, int u) {
    		if (l == r) {
    			t[u].first = t[u].second = b[l];
    			return;	
    		}
    		build(l, mid, lson); build(mid + 1, r, rson);
    		t[u] = merge(t[lson], t[rson]);	
    	}
    
    	void update(int c, int l, int r, int u) {
    		if (l == r) {
    			t[u].first = t[u].second = b[l];
    			return;
    		}
    		if (c <= mid)
    			update(c, l, mid, lson);
    		else update(c, mid + 1, r, rson);
    		t[u] = merge(t[lson], t[rson]);	
    	}
    
    	int query(int l, int r, int u, P tmp) {
    		if (l == r) {
    			if (tmp.first == -1)
    				return t[u].first != -1;
    			P g = merge(tmp, t[u]);
    			return g.first != -1;
    		}
    		P g = tmp.first == -1 ? t[lson] : merge(tmp, t[lson]);
    		if (g.first == -1)
    			return query(l, mid, lson, tmp);
    		else return mid - l + 1 + query(mid + 1, r, rson, g);
    	}
    }using namespace SegT;
    
    int main()
    {
    	n = rd;
    	for (int i = 1; i <= n; ++i)
    		a[i] = rd + 1, b[a[i]] = i;
    	for (int i = 2; i <= n; ++i) {
    		int u = rd;
    		f[i][0] = u;
    		to[u].push_back(i);
    		to[i].push_back(u);
    	}
    	dep[1] = 1; dfs(1);
    	for (int i = 1; i < 20; ++i)
    		for (int j = 1; j <= n; ++j)
    			f[j][i] = f[f[j][i - 1]][i - 1];
    	;
    	build(1, n, 1);
    	m = rd;
    	for (; m; --m) {
    		int typ = rd;
    		if (typ == 1) {
    			int u = rd, v = rd;
    			swap(a[u], a[v]);
    			swap(b[a[u]], b[a[v]]);
    
    			update(a[u], 1, n, 1);
    			update(a[v], 1, n, 1);
    		}		
    		else printf("%d
    ", query(1, n, 1, P(-1, -1)));
    	}
    }
    
    

    Max Mex

  • 相关阅读:
    powerpc调试工具的使用
    微软的开发工具是我见过比较难用的
    Spring之jdbcTemplate:查询的三种方式(单个值、单个对象、对象集合)
    静态工厂方法和实例工厂方法
    理解.NET Framework
    .NET相关的概念简介
    二、文档工具 swagger
    Java Web学习(二)数据加密
    Java Web学习(一)Web基础
    Oracle学习(十二)标量函数
  • 原文地址:https://www.cnblogs.com/cychester/p/10178804.html
Copyright © 2020-2023  润新知