zoukankan      html  css  js  c++  java
  • BZOJ3083 遥远的国度 【树剖】

    题目

    zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。

    问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。

    输入格式

    第1行两个整数n m,代表城市个数和操作数。
    第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。
    第n+1行,有n个整数,代表所有点的初始防御值。
    第n+2行一个整数 id,代表初始的首都为id。
    第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1 p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数 id,代表询问以城市id为根的子树中的最小防御值。

    输出格式

    对于每个opt=3的操作,输出一行代表对应子树的最小点权值。

    输入样例

    3 7

    1 2

    1 3

    1 2 3

    1

    3 1

    2 1 1 6

    3 1

    2 2 2 5

    3 1

    2 3 3 4

    3 1

    输出样例

    1

    2

    3

    4

    提示

    对于20%的数据,n<=1000 m<=1000。

    对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。

    对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。

    对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。

    对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。

    题解

    树剖,较为休闲
    主要是换根问题,只影响询问结果
    如果根与询问节点u的lca不为u,说明根在原树u的子树外,这样子换根后u的子树不变
    如果lca为u,那么换根后只有根所在原树u的子树不在换根后u的子树内

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define ls (u << 1)
    #define rs (u << 1 | 1)
    using namespace std;
    const int maxn = 100005,maxm = 100005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
    	return out * flag;
    }
    int h[maxn],ne = 2;
    struct EDGE{int to,nxt;}ed[2 * maxn];
    inline void build(int u,int v){
    	ed[ne] = (EDGE){v,h[u]}; h[u] = ne++;
    	ed[ne] = (EDGE){u,h[v]}; h[v] = ne++;
    }
    int n,m,val[maxn],capi;
    int siz[maxn],dep[maxn],fa[maxn][18],top[maxn],son[maxn],id[maxn],Hash[maxn],cnt;
    void dfs1(int u){
    	siz[u] = 1;
    	REP(i,17) fa[u][i] = fa[fa[u][i - 1]][i - 1];
    	Redge(u) if ((to = ed[k].to) != fa[u][0]){
    		dep[to] = dep[u] + 1; fa[to][0] = u;
    		dfs1(to);
    		siz[u] += siz[to];
    		if (!son[u] || siz[to] > siz[son[u]]) son[u] = to;
    	}
    }
    void dfs2(int u,int flag){
    	id[u] = ++cnt; Hash[cnt] = u;
    	top[u] = flag ? top[fa[u][0]] : u;
    	if (son[u]) dfs2(son[u],true);
    	Redge(u) if ((to = ed[k].to) != fa[u][0] && to != son[u])
    		dfs2(to,false);
    }
    int mn[4 * maxn],tag[4 * maxn];
    void pd(int u){
    	if (tag[u]) mn[ls] = mn[rs] = tag[ls] = tag[rs] = tag[u],tag[u] = 0;
    }
    void build(int u,int l,int r){
    	if (l == r){
    		mn[u] = val[Hash[l]];
    		return;
    	}
    	int mid = l + r >> 1;
    	build(ls,l,mid);
    	build(rs,mid + 1,r);
    	mn[u] = min(mn[ls],mn[rs]);
    }
    void modify(int u,int l,int r,int L,int R,int v){
    	if (l >= L && r <= R){mn[u] = tag[u] = v; return;}
    	pd(u);
    	int mid = l + r >> 1;
    	if (mid >= L) modify(ls,l,mid,L,R,v);
    	if (mid < R) modify(rs,mid + 1,r,L,R,v);
    	mn[u] = min(mn[ls],mn[rs]);
    }
    int query(int u,int l,int r,int L,int R){
    	if (l >= L && r <= R) return mn[u];
    	pd(u);
    	int mid = l + r >> 1;
    	if (mid >= R) return query(ls,l,mid,L,R);
    	else if (mid < L) return query(rs,mid + 1,r,L,R);
    	else return min(query(ls,l,mid,L,R),query(rs,mid + 1,r,L,R));
    }
    int Lca(int u,int v){
    	if (dep[u] < dep[v]) swap(u,v);
    	if (dep[u] != dep[v]){
    		for (int i = 0,d = dep[u] - dep[v] - 1; (1 << i) <= d; i++)
    			if (d & (1 << i)) u = fa[u][i];
    		if (fa[u][0] == v) return u;
    		u = fa[u][0];
    	}
    	for (int i = 17; i >= 0; i--)
    		if (fa[u][i] != fa[v][i]) u = fa[u][i],v = fa[v][i];
    	return u;
    }
    void solve1(int u,int v,int x){
    	while (top[u] != top[v]){
    		if (dep[top[u]] < dep[top[v]]) swap(u,v);
    		modify(1,1,n,id[top[u]],id[u],x);
    		u = fa[top[u]][0];
    	}
    	if (dep[u] > dep[v]) swap(u,v);
    	modify(1,1,n,id[u],id[v],x);
    }
    void solve2(int u){
    	if (u == capi) {printf("%d
    ",mn[1]); return;}
    	int lca = Lca(u,capi);
    	if (fa[lca][0] != u) printf("%d
    ",query(1,1,n,id[u],id[u] + siz[u] - 1));
    	else {
    		int L = id[lca] - 1,R = id[lca] + siz[lca];
    		printf("%d
    ",min(query(1,1,n,1,L),R <= n ? query(1,1,n,R,n) : INF));
    	}
    }
    int main(){
    	n = read(); m = read();
    	for (int i = 1; i < n; i++) build(read(),read());
    	for (int i = 1; i <= n; i++) val[i] = read();
    	dfs1(1); dfs2(1,0); build(1,1,n);
    	capi = read();
    	int opt,u,v;
    	while (m--){
    		opt = read();
    		if (opt == 1) capi = read();
    		else if (opt == 2){
    			u = read(); v = read();
    			solve1(u,v,read());
    		}else solve2(read());
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Verilog杂谈
    Hadoop家族学习路线图
    R语言中apply函数
    R语言数组array函数
    R语言列表list函数
    R语言多元素向量
    R语言提取字符串的一部分substring函数
    R语言改变大小写 toupper()和 tolower()函数
    R语言统计字符串的字符数ncahr函数
    R语言格式化数字和字符串format函数
  • 原文地址:https://www.cnblogs.com/Mychael/p/8479898.html
Copyright © 2011-2022 走看看