zoukankan      html  css  js  c++  java
  • 【树链剖分换根】P3979 遥远的国度

    Description

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

    问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。

    RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。

    由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。

    Input

    第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为根的子树中的最小防御值。

    Output

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

    Solution

    换根板子题。

    先钦定1是根dfs树剖一波,然后考虑几个操作。

    链修改的操作和树形没关系,直接做。

    考虑查询操作,画图以后可以发现,当一个点(u)不在点(v)的子树中时(原树上),以点(u)为根时(v)的子树形态不变。证明可以考虑此时(u)一定是通过(v)的父亲和(v)连接的,换根后还是通过(v)的父亲,而其他的子树显然还在(u)下方。在此不做展开。

    当点(u)(v)的子树内时,发现(u)(v)是通过指向(u)的儿子链接的。于是(u)的那个儿子儿子所能连接到的所有点(除通过(v)连接的以外)都会在新树上直接作为(u)的子树而不是(v)的子树,剩下的就是(v)的子树了。而那个儿子能链接的所有点恰好是该儿子的子树。于是查询时查询整棵树去掉该儿子子树的min即可。

    另外特判(v)是根的情况。直接查询子树

    Code

    #include <cstdio>
    #include <algorithm>
    #ifdef ONLINE_JUDGE
    #define freopen(a, b, c)
    #endif
    #define rg register
    #define ci const int
    #define cl const long long
    
    typedef long long int ll;
    
    namespace IPT {
    	const int L = 1000000;
    	char buf[L], *front=buf, *end=buf;
    	char GetChar() {
    		if(front == end) {
    			end = buf + fread(front = buf, 1, L, stdin);
    			if(front == end) return -1;
    		}
    		return *(front++);
    	}
    }
    
    template <typename T>
    inline void qr(T &x) {
    	rg char ch = IPT::GetChar(), lst = ' ';
    	while((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
    	while((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
    	if(lst == '-') x = -x;
    }
    
    template <typename T>
    inline void ReadDb(T &x) {
    	rg char ch = IPT::GetChar(), lst = ' ';
    	while((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
    	while((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
    	if(ch == '.') {
    		ch = IPT::GetChar();
    		double base = 1;
    		while((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
    	}
    	if(lst == '-') x = -x;
    }
    
    namespace OPT {
    	char buf[120];
    }
    
    template <typename T>
    inline void qw(T x, const char aft, const bool pt) {
    	if(x < 0) {x = -x, putchar('-');}
    	rg int top=0;
    	do {OPT::buf[++top] = x % 10 + '0';} while( x /= 10);
    	while(top) putchar(OPT::buf[top--]);
    	if(pt) putchar(aft);
    }
    
    const int maxn = 100010;
    const int maxm = 200010;
    
    struct Edge {
    	int to, nxt;
    };
    Edge edge[maxm]; int hd[maxn], ecnt=1;
    inline void cont(ci from, ci to) {
    	Edge &e = edge[++ecnt];
    	e.to = to; e.nxt = hd[from]; hd[from] = ecnt;
    }
    
    int n, m, vistime, newrot;
    int sz[maxn], dfn[maxn], otn[maxn], son[maxn], top[maxn], rmp[maxn], MU[maxn], deepth[maxn], fa[maxn];
    
    const int INF = (1ll << 31) - 1;
    
    struct Tree {
    	Tree *ls, *rs;
    	int v, tag, l, r;
    	
    	inline void pushup() {
    		this->v = INF;
    		if(this->ls) this->v = this->ls->v;
    		if(this->rs) this->v = std::min(this->rs->v, this->v);
    	}
    	
    	inline void maketag(ci _v) {
    		this->v = _v;
    		this->tag = _v;
    	}
    	
    	inline void pushdown() {
    		if(!this->tag) return;
    		if(this->ls) this->ls->maketag(this->tag);
    		if(this->rs) this->rs->maketag(this->tag);
    		this->tag = 0;
    	}
    };
    Tree *pool[maxm],qwq[maxm],*rot;
    int poltp;
    
    void reading();
    void dfs(ci, ci);
    void DFS(ci, ci);
    void buildpool();
    void buildroot();
    void build(Tree*, ci, ci);
    void change(int, int, int);
    void update(Tree*, ci, ci, ci);
    int ask(Tree*, ci, ci);
    
    int main() {
    	freopen("1.in", "r", stdin);
    	qr(n); qr(m);
    	reading();
    	qr(newrot) ;
    	dfs(newrot, 0); DFS(newrot, newrot);
    	buildpool(); buildroot();
    	build(rot, 1, n);
    	int a, b, c, d;
    	while (m--) {
    		a = 0; qr(a);
    		if (a == 1) {
    			newrot = 0; qr(newrot);
    		} else if (a == 2) {
    			b = c = d = 0; qr(b); qr(c); qr(d);
    			change(b, c, d);
    		} else if (a == 3) {
    			a=0; qr(a);
    			if (a == newrot) {
    				qw(rot->v, '
    ', true);
    			} else if ((dfn[newrot] >= dfn[a]) && (dfn[newrot] <= otn[a])) {
    				int tp = newrot;
    				while(deepth[fa[top[tp]]] > deepth[a]) tp = fa[top[tp]];
    				if(dfn[top[tp]] > dfn[a]) tp = top[tp];
    				else tp = rmp[dfn[a] + 1];
    				qw(std::min(ask(rot, 1, dfn[tp] - 1), ask(rot, otn[tp]+1, n)), '
    ', true);
    			} else {
    				qw(ask(rot,dfn[a],otn[a]), '
    ', true);
    			}
    		}
    	}
    	return 0;
    }
    
    void reading() {
    	int a,b;
    	for (rg int i = 1; i < n; ++i) {
    		a = b = 0; qr(a); qr(b);
    		cont(a, b); cont(b, a);
    	}
    	for(rg int i = 1; i <= n; ++i) qr(MU[i]);
    }
    
    void dfs(ci u, ci pree) {
    	sz[u] = 1;
    	deepth[u] = deepth[fa[u] = edge[pree].to] + 1;
    	for (int i = hd[u]; i; i = edge[i].nxt) if (i != pree) {
    		int &to = edge[i].to;
    		dfs(to, i^1);
    		if(sz[to] > sz[son[u]]) son[u] = to;
    	}
    }
    
    void DFS(ci u, ci tp) {
    	if((!u) || (dfn[u])) return;
    	dfn[u] = ++vistime;
    	rmp[vistime] = u;
    	top[u] = tp;
    	DFS(son[u], tp);
    	for (int i = hd[u]; i; i = edge[i].nxt) {
    		int &to = edge[i].to;
    		if(to  == son[u]) continue;
    		DFS(to,to);
    	}
    	otn[u] = vistime;
    }
    
    void buildpool() {
    	for (rg int i = 0; i < maxm; ++i) pool[i] = qwq+i;
    	poltp = maxm - 1;
    }
    
    inline void buildroot() {
    	rot = pool[poltp--];
    }
    
    void build(Tree *u, ci l, ci r) {
    	u->l = l; u->r = r;
    	if(l == r) {
    		u->v = MU[rmp[l]];
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if(l <= mid) {
    		u->ls = pool[poltp--];
    		build(u->ls, l, mid);
    	}
    	if(mid < r) {
    		u->rs = pool[poltp--];
    		build(u->rs, mid+1, r);
    	}
    	u->pushup();
    }
    
    void change(int u, int v, int p) {
    	while(top[u] != top[v]) {
    		if(deepth[top[u]] < deepth[top[v]]) std::swap(u, v);
    		update(rot, dfn[top[u]], dfn[u], p);
    		u = fa[top[u]];
    	}
    	if(deepth[u] < deepth[v]) std::swap(u, v);
    	update(rot, dfn[v], dfn[u], p);
    }
    
    void update(Tree *u, ci l, ci r, ci v) {
    	if((u->l > r) || (u->r < l)) return;
    	if((u->l >= l) && (u->r <= r)) {u->maketag(v); return;}
    	u->pushdown();
    	if(u->ls) update(u->ls, l, r, v);
    	if(u->rs) update(u->rs, l, r, v);
    	u->pushup();
    }
    
    int ask(Tree *u, ci l, ci r) {
    	if((u->l > r) || (u->r < l)) return INF;
    	if((u->l >= l) && (u->r <= r)) return u->v;
    	u->pushdown();
    	int _ret = INF;
    	if(u->ls) _ret = ask(u->ls, l, r);
    	if(u->rs) _ret = std::min(ask(u->rs, l, r), _ret);
    	return _ret;
    }
    

    Summary

    树上的链操作与根无关

    涉及到子树的操作可以通过讨论解决。

  • 相关阅读:
    How To Scan QRCode For UWP (4)
    How To Crop Bitmap For UWP
    How To Scan QRCode For UWP (3)
    How To Scan QRCode For UWP (2)
    How To Scan QRCode For UWP (1)
    How to change windows applicatioin's position via Win32 API
    8 Ways to Become a Better Coder
    How to resize or create a thumbnail image from file stream on UWP
    C# winform压缩文件夹带进度条
    MS ACCESS MID函数
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/10034761.html
Copyright © 2011-2022 走看看