zoukankan      html  css  js  c++  java
  • SPOJ Qtree系列

    Qtree1

    将边权变为这条边连接的两个点中深度更深的点的点权,这样就可以变为带修改链上最大点权。直接树链剖分即可。

    下面是一份C语言代码

    #include<stdio.h>
    #include<string.h>
    #define MAXN 10001
    inline int read(){
        int a = 0;
        int f = 0;
        char c = getchar();
        while(!isdigit(c)){
            if(c == '-')
                f = 1;
            c = getchar();
        }
        while(isdigit(c)){
            a = (a << 3) + (a << 1) + (c ^ '0');
            c = getchar();
        }
        return f ? -a : a;
    }
    
    char output[20];
    inline void print(int x){
        int dirN = 18;
        if(x == 0)
        	fwrite("0" , sizeof(char) , 1 , stdout);
        else{
        	if(x < 0){
        		x = -x;
        		fwrite("-" , sizeof(char) , 1 , stdout);
            }
            while(x){
           	    output[--dirN] = x % 10 + 48;
        	    x /= 10;
        	}
        	fwrite(output + dirN , 1 , strlen(output + dirN) , stdout);
        }
        fwrite("
    " , 1 , 1 , stdout);
    }
    
    inline int max(int a , int b){
        return a > b ? a : b;
    }
    
    struct node{
        int l , r , maxN;
    }Tree[MAXN << 2];
    struct Edge{
        int end , upEd , w;
    }Ed[MAXN << 1];
    int head[MAXN] , start[MAXN << 1] , size[MAXN] , son[MAXN] , fa[MAXN] , dep[MAXN];
    int top[MAXN] , ind[MAXN] , rk[MAXN] , val[MAXN] , N , cntEd , ts;
    
    inline void addEd(int a , int b , int c){
        Ed[++cntEd].end = b;
        Ed[cntEd].upEd = head[a];
        Ed[cntEd].w = c;
        head[a] = cntEd;
    }
    
    void dfs1(int dir , int father , int w){
        val[dir] = w;
        dep[dir] = dep[fa[dir] = father] + 1;
        size[dir] = 1;
        int i;
        for(i = head[dir] ; i ; i = Ed[i].upEd)
            if(!dep[Ed[i].end]){
                dfs1(Ed[i].end , dir , Ed[i].w);
                size[dir] += size[Ed[i].end];
                if(size[son[dir]] < size[Ed[i].end])
                    son[dir] = Ed[i].end;
            }
    }
    
    void dfs2(int dir , int t){
        top[dir] = t;
        rk[ind[dir] = ++ts] = dir;
        if(!son[dir])
            return;
        dfs2(son[dir] , t);
        int i;
        for(i = head[dir] ; i ; i = Ed[i].upEd)
            if(Ed[i].end != fa[dir] && Ed[i].end != son[dir])
                dfs2(Ed[i].end , Ed[i].end);
    }
    
    inline void pushup(int dir){
        Tree[dir].maxN = max(Tree[dir << 1].maxN , Tree[dir << 1 | 1].maxN);
    }
    
    void init(int dir , int l , int r){
        Tree[dir].l = l;
        Tree[dir].r = r;
        if(l == r)
            Tree[dir].maxN = val[rk[l]];
        else{
            init(dir << 1 , l , l + r >> 1);
            init(dir << 1 | 1 , (l + r >> 1) + 1 , r);
            pushup(dir);
        }
    }
    
    void change(int dir , int tar , int val){
        if(Tree[dir].l == Tree[dir].r){
            Tree[dir].maxN = val;
            return;
        }
        if(Tree[dir].l + Tree[dir].r >> 1 >= tar)
            change(dir << 1 , tar , val);
        else
            change(dir << 1 | 1 , tar , val);
        pushup(dir);
    }
    
    int findMax(int dir , int l , int r){
        if(Tree[dir].l >= l && Tree[dir].r <= r)
            return Tree[dir].maxN;
        int maxN = 0;
        if(l <= Tree[dir].l + Tree[dir].r >> 1)
            maxN = max(maxN , findMax(dir << 1 , l , r));
        if(r > Tree[dir].l + Tree[dir].r >> 1)
            maxN = max(maxN , findMax(dir << 1 | 1 , l , r));
        return maxN;
    }
    
    inline void work(int x , int y){
        if(x == y){
            print(0);
            return;
        }
        int tx = top[x] , ty = top[y] , maxN = -0x7fffffff;
        while(tx != ty)
            if(dep[tx] >= dep[ty]){
                maxN = max(maxN , findMax(1 , ind[tx] , ind[x]));
                x = fa[tx];
                tx = top[x];
            }
            else{
                maxN = max(maxN , findMax(1 , ind[ty] , ind[y]));
                y = fa[ty];
                ty = top[y];
            }
        if(ind[x] < ind[y])
            maxN = max(maxN , findMax(1 , ind[x] + 1 , ind[y]));
        if(ind[y] < ind[x])
            maxN = max(maxN , findMax(1 , ind[y] + 1 , ind[x]));
        print(maxN);
    }
    
    int cmp(int a , int b){
        return dep[a] < dep[b] ? ind[b] : ind[a];
    }
    
    char s[10];
    int main(){
        int T;
        for(T = read() ; T ; T--){
        	N = read();
        	memset(head , 0 , sizeof(head));
        	memset(dep , 0 , sizeof(dep));
        	memset(start , 0 , sizeof(start));
        	memset(size , 0 , sizeof(size));
        	memset(son , 0 , sizeof(son));
        	memset(fa , 0 , sizeof(fa));
        	memset(top , 0 , sizeof(top));
        	memset(ind , 0 , sizeof(ind));
        	memset(rk , 0 , sizeof(rk));
        	memset(val , 0 , sizeof(val));
        	cntEd = ts = 0;
        	int i;
            for(i = 1 ; i < N ; i++){
        	    start[(i << 1) - 1] = read();
        	    start[i << 1] = read();
        	    int c = read();
        	    addEd(start[(i << 1) - 1] , start[i << 1] , c);
        	    addEd(start[i << 1] , start[(i << 1) - 1] , c);
        	}
        	dfs1(1 , 0 , 0);
        	dfs2(1 , 1);
        	init(1 , 1 , N);
        	while(scanf("%s" , s) && s[0] != 'D'){
        	    int a = read() , b = read();
        	    if(s[0] == 'Q')
        	        work(a , b);
        	    else
        	        change(1 , cmp(start[a << 1] , start[(a << 1) - 1]) , b);
        	}
        }
        return 0;
    }
    

    Qtree2

    同样先把边权变为较深的点的点权,那么这两个操作都可以通过倍增+维护倍增经过的所有点的点权和完成。

        #include<bits/stdc++.h>
        //This code is written by Itst
        using namespace std;
         
        inline int read(){
        	int a = 0;
        	bool f = 0;
        	char c = getchar();
        	while(c != EOF && !isdigit(c)){
        		if(c == '-')
        			f = 1;
        		c = getchar();
        	}
        	while(c != EOF && isdigit(c)){
        		a = (a << 3) + (a << 1) + (c ^ '0');
        		c = getchar();
        	}
        	return f ? -a : a;
        }
         
        const int MAXN = 10010;
        struct Edge{
        	int end , upEd , w;
        }Ed[MAXN << 1];
        int jump[MAXN][21][2] , head[MAXN] , dep[MAXN];
        int N , cntEd;
         
        inline void addEd(int a , int b , int c){
        	Ed[++cntEd].end = b;
        	Ed[cntEd].upEd = head[a];
        	Ed[cntEd].w = c;
        	head[a] = cntEd;
        }
         
        void dfs(int x , int f){
        	jump[x][0][0] = f;
        	dep[x] = dep[f] + 1;
        	for(int i = 1 ; jump[x][i - 1][0] ; ++i){
        		jump[x][i][0] = jump[jump[x][i - 1][0]][i - 1][0];
        		jump[x][i][1] = jump[x][i - 1][1] + jump[jump[x][i - 1][0]][i - 1][1];
        	}
        	for(int i = head[x] ; i ; i = Ed[i].upEd)
        		if(Ed[i].end != f){
        			jump[Ed[i].end][0][1] = Ed[i].w;
        			dfs(Ed[i].end , x);
        		}
        }
         
        inline pair < int , int > LCA(int x , int y){
        	int sum = 0;
        	if(dep[x] < dep[y])
        		swap(x , y);
        	for(int i = 20 ; i >= 0 ; --i)
        		if(dep[x] - (1 << i) >= dep[y]){
        			sum += jump[x][i][1];
        			x = jump[x][i][0];
        		}
        	if(x == y)
        		return make_pair(x , sum);
        	for(int i = 20 ; i >= 0 ; --i)
        		if(jump[x][i][0] != jump[y][i][0]){
        			sum += jump[x][i][1] + jump[y][i][1];
        			x = jump[x][i][0];
        			y = jump[y][i][0];
        		}
        	return make_pair(jump[x][0][0] , sum + jump[x][0][1] + jump[y][0][1]);
        }
         
        inline int Kth(int x , int y , int k){
        	int t = LCA(x , y).first;
        	if(dep[x] - dep[t] + 1 >= k){
        		--k;
        		for(int i = 16 ; i >= 0 ; --i)
        			if(k & (1 << i))
        				x = jump[x][i][0];
        		return x;
        	}
        	else{
        		k = dep[x] + dep[y] - (dep[t] << 1) + 1 - k;
        		for(int i = 16 ; i >= 0 ; --i)
        			if(k & (1 << i))
        				y = jump[y][i][0];
        		return y;
        	}
        }
         
        inline char getc(){
        	char c = getchar();
        	while(!isupper(c))
        		c = getchar();
        	return c = getchar();
        }
         
        int main(){
        	for(int T = read() ; T ; --T){
        		memset(head , 0 , sizeof(head));
        		memset(jump , 0 , sizeof(jump));
        		cntEd = 0;
        		N = read();
        		for(int i = 1 ; i < N ; ++i){
        			int a = read() , b = read() , c = read();
        			addEd(a , b , c);
        			addEd(b , a , c);
        		}
        		dfs(1 , 0);
        		int a , b , c;
        		bool f = 1;
        		while(f)
        			switch(getc()){
        			case 'I':
        				printf("%d
    " , LCA(read() , read()).second);
        				break;
        			case 'T':
        				a = read();
        				b = read();
        				c = read();
        				printf("%d
    " , Kth(a , b , c));
        				break;
        			default:
        				f = 0;
        			}
        		cout << endl;
            }
    	return 0;
        }
    

    Qtree3

    一样是树链剖分,线段树上每一个点维护这一段区间中dfn序最大的黑点的dfn序。

    #include<bits/stdc++.h>
    #define MAXN 100001
    using namespace std;
    
    namespace IO{
        const int maxn((1 << 21) + 1);
        char ibuf[maxn], *iS, *iT, obuf[maxn], *oS = obuf, *oT = obuf + maxn - 1, c, st[55];
        int f, tp;
        char Getc() {
            return (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, maxn, stdin), (iS == iT ? EOF : *iS++)) : *iS++);
        }
        void Flush() {
            fwrite(obuf, 1, oS - obuf, stdout);
            oS = obuf;
        }
        void Putc(char x) {
            *oS++ = x;
            if (oS == oT) Flush();
        }
        template <class Int> void Input(Int &x) {
            for (f = 1, c = Getc(); c < '0' || c > '9'; c = Getc()) f = c == '-' ? -1 : 1;
            for (x = 0; c <= '9' && c >= '0'; c = Getc()) x = (x << 3) + (x << 1) + (c ^ 48);
            x *= f;
        }
        template <class Int> void Print(Int x) {
            if (!x) Putc('0');
            if (x < 0) Putc('-'), x = -x;
            while (x) st[++tp] = x % 10 + '0', x /= 10;
            while (tp) Putc(st[tp--]);
    	}
        void Getstr(char *s, int &l) {
            for (c = Getc(); c < 'a' || c > 'z'; c = Getc());
            for (l = 0; c <= 'z' && c >= 'a'; c = Getc()) s[l++] = c;
            s[l] = 0;
        }
        void Putstr(const char *s) {
            for (int i = 0, n = strlen(s); i < n; ++i) Putc(s[i]);
        }
    }
    using namespace IO;
    
    struct node{
    	int l , r , minN;
    }Tree[MAXN << 2];
    struct Edge{
    	int end , upEd;
    }Ed[MAXN << 1];
    int son[MAXN] , size[MAXN] , fa[MAXN] , dep[MAXN] , head[MAXN];
    int top[MAXN] , ind[MAXN] , rk[MAXN] , N , cntEd , ts;
    
    inline void addEd(int a , int b){
    	Ed[++cntEd].end = b;
    	Ed[cntEd].upEd = head[a];
    	head[a] = cntEd;
    }
    
    void dfs1(int dir , int father){
    	size[dir] = 1;
    	dep[dir] = dep[fa[dir] = father] + 1;
    	for(int i = head[dir] ; i ; i = Ed[i].upEd)
    		if(!dep[Ed[i].end]){
    			dfs1(Ed[i].end , dir);
    			size[dir] += size[Ed[i].end];
    			if(size[son[dir]] < size[Ed[i].end])
    				son[dir] = Ed[i].end;
    		}
    }
    
    void dfs2(int dir , int t){
    	top[dir] = t;
    	rk[ind[dir] = ++ts] = dir;
    	if(!son[dir])
    		return;
    	dfs2(son[dir] , t);
    	for(int i = head[dir] ; i ; i = Ed[i].upEd)
    		if(Ed[i].end != son[dir] && Ed[i].end != fa[dir])
    			dfs2(Ed[i].end , Ed[i].end);
    }
    
    inline int min(int a , int b){
    	return a < b ? a : b;
    }
    
    void init(int dir , int l , int r){
    	Tree[dir].l = l;
    	Tree[dir].r = r;
    	if(l == r)
    		Tree[dir].minN = 999999;
    	else{
    		init(dir << 1 , l , (l + r) >> 1);
    		init(dir << 1 | 1 , ((l + r) >> 1) + 1 , r);
    		Tree[dir].minN = min(Tree[dir << 1].minN , Tree[dir << 1 | 1].minN);
    	}
    }
    
    void change(int dir , int tar){
    	if(Tree[dir].l == Tree[dir].r){
    		Tree[dir].minN = Tree[dir].minN == 999999 ? Tree[dir].l : 999999;
    		return;
    	}
    	if(tar <= (Tree[dir].l + Tree[dir].r) >> 1)
    		change(dir << 1 , tar);
    	else
    		change(dir << 1 | 1 , tar);
    	Tree[dir].minN = min(Tree[dir << 1].minN , Tree[dir << 1 | 1].minN);
    }
    
    int findMin(int dir , int l , int r){
    	if(Tree[dir].l >= l && Tree[dir].r <= r)
    		return Tree[dir].minN;
    	int minN;
    	if(l <= (Tree[dir].l + Tree[dir].r) >> 1){
    		minN = findMin(dir << 1 , l , r);
    		if(minN != 999999)
    			return minN;
    	}
    	if(r > (Tree[dir].l + Tree[dir].r) >> 1)
    		return findMin(dir << 1 | 1 , l , r);
    	return 999999;
    }
    
    inline int work(int tar){
    	int minN = 999999;
    	while(top[tar] != 1){
    		minN = min(minN , findMin(1 , ind[top[tar]] , ind[tar]));
    		tar = fa[top[tar]];
    	}
    	minN = min(minN , findMin(1 , 1 , ind[tar]));
    	return minN == 999999 ? -1 : rk[minN];
    }
    
    int main(){
    	int N , M;
    	Input(N);
    	Input(M);
    	for(int i = 1 ; i < N ; i++){
    		int a , b;
    		Input(a);
    		Input(b);
    		addEd(a , b);
    		addEd(b , a);
    	}
    	dfs1(1 , 0);
    	dfs2(1 , 1);
    	init(1 , 1 , N);
    	while(M--){
    		int a;
    		Input(a);
    		if(a == 0){
    			Input(a);
    			change(1 , ind[a]);
    		}
    		else{
    			Input(a);
    			Print(work(a));
    			Putc('
    ');
    		}
    	}
    	Flush();
    	return 0;
    }
    

    Qtree4

    动态点分的学习笔记里面

    Qtree5

    仍然是动态点分,对于每一个点维护其所有点分树子树中的白点到当前点的最短距离。修改和查询都暴力跳点分树。

    注意到从一个子树中走到分治中心再走回去一定不优,所以并不需要维护到父亲的堆。

    #include<bits/stdc++.h>
    #define INF (int)1e9
    //This code is written by Itst
    using namespace std;
    
    inline int read(){
    	int a = 0;
    	bool f = 0;
    	char c = getchar();
    	while(c != EOF && !isdigit(c)){
    		if(c == '-')
    			f = 1;
    		c = getchar();
    	}
    	while(c != EOF && isdigit(c)){
    		a = (a << 3) + (a << 1) + (c ^ '0');
    		c = getchar();
    	}
    	return f ? -a : a;
    }
    
    const int MAXN = 100010;
    struct Edge{
    	int end , upEd;
    }Ed[MAXN << 1];
    int head[MAXN] , dep[MAXN] , fir[MAXN] , ST[21][MAXN << 1] , logg2[MAXN << 1] , fa[MAXN][20] , size[MAXN] , dis[MAXN][20];
    int N , nowSize , minSize , minInd , cntST , cntEd;
    bool vis[MAXN] , col[MAXN];
    struct pq{
    	priority_queue < int , vector < int > , greater < int > > q1 , q2;
    
    	inline void maintain(){
    		while(!q1.empty() && !q2.empty() && q1.top() == q2.top()){
    			q1.pop();
    			q2.pop();
    		}
    	}
    	
    	inline void push(int x){
    		q1.push(x);
    	}
    
    	inline void pop(int x){
    		q2.push(x);
    	}
    
    	inline int top(){
    		maintain();
    		return q1.empty() ? INF : q1.top();
    	}
    	
    }cur[MAXN];
    
    inline void addEd(int a , int b){
    	Ed[++cntEd].end = b;
    	Ed[cntEd].upEd = head[a];
    	head[a] = cntEd;
    }
    
    void init_dfs(int x , int pre){
    	dep[x] = dep[pre] + 1;
    	fir[x] = ++cntST;
    	ST[0][cntST] = x;
    	for(int i = head[x] ; i ; i = Ed[i].upEd)
    		if(Ed[i].end != pre){
    			init_dfs(Ed[i].end , x);
    			ST[0][++cntST] = x;
    		}
    }
    
    inline int cmp(int a , int b){
    	return dep[a] < dep[b] ? a : b;
    }
    
    void init_st(){
    	for(int i = 2 ; i <= cntST ; ++i)
    		logg2[i] = logg2[i >> 1] + 1;
    	for(int i = 1 ; 1 << i <= cntST ; ++i)
    		for(int j = 1 ; j + (1 << i) - 1 <= cntST ; ++j)
    			ST[i][j] = cmp(ST[i - 1][j] , ST[i - 1][j + (1 << (i - 1))]);
    }
    
    inline int LCA(int x , int y){
    	x = fir[x];
    	y = fir[y];
    	if(x > y)
    		swap(x , y);
    	int t = logg2[y - x + 1];
    	return cmp(ST[t][x] , ST[t][y - (1 << t) + 1]);
    }
    
    inline int calcLen(int x , int y){
    	return dep[x] + dep[y] - (dep[LCA(x , y)] << 1);
    }
    
    void getSize(int x){
    	vis[x] = 1;
    	++nowSize;
    	for(int i = head[x] ; i ; i = Ed[i].upEd)
    		if(!vis[Ed[i].end])
    			getSize(Ed[i].end);
    	vis[x] = 0;
    }
    
    void getRoot(int x){
    	int maxN = 0;
    	vis[x] = size[x] = 1;
    	for(int i = head[x] ; i ; i = Ed[i].upEd)
    		if(!vis[Ed[i].end]){
    			getRoot(Ed[i].end);
    			size[x] += size[Ed[i].end];
    			maxN = max(maxN , size[Ed[i].end]);
    		}
    	maxN = max(maxN , nowSize - size[x]);
    	if(maxN < minSize){
    		minSize = maxN;
    		minInd = x;
    	}
    	vis[x] = 0;
    }
    
    void init_dfz(int x , int p){
    	nowSize = 0;
    	minSize = 0x7fffffff;
    	getSize(x);
    	getRoot(x);
    	x = minInd;
    	vis[x] = 1;
    	fa[x][0] = p;
    	for(int i = 0 ; fa[x][i] ; ++i){
    		fa[x][i + 1] = fa[fa[x][i]][0];
    		dis[x][i] = calcLen(x , fa[x][i]);
    	}
    	for(int i = head[x] ; i ; i = Ed[i].upEd)
    		if(!vis[Ed[i].end])
    			init_dfz(Ed[i].end , x);
    }
    
    void init(){
    	init_dfs(1 , 0);
    	init_st();
    	init_dfz(1 , 0);
    }
    
    inline int query(int x){
    	int minN = cur[x].top();
    	for(int i = 0 ; fa[x][i] ; ++i)
    		minN = min(minN , cur[fa[x][i]].top() + dis[x][i]);
    	return minN == INF ? -1 : minN;
    }
    
    inline void modify(int x){
    	vis[x] ^= 1;
    	vis[x] ? cur[x].pop(0) : cur[x].push(0);
    	for(int i = 0 ; fa[x][i] ; ++i)
    		vis[x] ? cur[fa[x][i]].pop(dis[x][i]) : cur[fa[x][i]].push(dis[x][i]);
    }
    
    int main(){
    	N = read();
    	for(int i = 1 ; i < N ; ++i){
    		int a = read() , b = read();
    		addEd(a , b);
    		addEd(b , a);
    	}
    	init();
    	for(int M = read() ; M ; --M)
    		if(read())
    			printf("%d
    " , query(read()));
    		else
    			modify(read());
    	return 0;
    }
    

    Qtree6

    考虑LCT。维护点的颜色连通块似乎不好做,因为是否连通实际上是和边相关的一个东西。我们考虑每一个点,当这个点是黑色的时候在黑色的LCT上将它和它的父亲连边,否则在白色的LCT上连边。这样对于黑白两色的LCT,去掉每一个连通块的root后,剩余的每一个连通块就是当前颜色的一个颜色连通块。

    那么我们按照这个进行Link、Cut,并在每一次询问的时候先access保证当前点在整棵树的实链上,然后findroot并将root splay至根,最后输出根的右儿子的size即可。

    值得注意的是在Link和Cut中不能够进行平常需要在其中进行的makeroot操作,因为这样会改变每一个连通块的根。我们可以这样修改:

    Link:每一次进行Link操作的点都一定是当前连通块的根,所以直接splay至LCT的根即可;

    Cut:因为每一次要cut的边连接的两个点的父子关系确定,所以可以不进行makeroot,直接对子节点access、splay并去掉对应的边。

    至于如何维护子树size,可以维护一个变量表示当前点的虚子树size和,不难发现只有在link和access的时候会改变这个量,这样就可以进行整个子树的维护。值得注意的是维护虚子树信息在link的时候要将父节点先access、splay到LCT的根,这样可以避免更新子树大小之后的一系列pushup。

    #include<bits/stdc++.h>
    using namespace std;
    
    int read(){
    	int a = 0; char c = getchar(); bool f = 0;
    	while(!isdigit(c)){f = c == '-'; c = getchar();}
    	while(isdigit(c)){
    		a = a * 10 + c - 48; c = getchar();
    	}
    	return f ? -a : a;
    }
    
    const int _ = 2e5 + 3;
    int fa[_] , ch[_][2] , sz[_] , vir[_]; bool rmrk[_];
    
    struct Edge{int end , upEd;}Ed[_ << 1];
    int pre[_] , head[_] , col[_] , cntEd , N , M;
    void addEd(int a , int b){Ed[++cntEd] = (Edge){b , head[a]}; head[a] = cntEd;}
    void dfs(int x , int p){pre[x] = p; for(int i = head[x] ; i ; i = Ed[i].upEd) if(Ed[i].end != p) dfs(Ed[i].end , x);}
    
    bool nroot(int x){return ch[fa[x]][0] == x || ch[fa[x]][1] == x;}
    bool son(int x){return ch[fa[x]][1] == x;}
    void up(int x){sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1 + vir[x];}
    
    void rot(int x){
    	bool f = son(x); int y = fa[x] , z = fa[y] , w = ch[x][f ^ 1];
    	fa[x] = z; if(nroot(y)) ch[z][son(y)] = x;
    	fa[y] = x; ch[x][f ^ 1] = y;
    	ch[y][f] = w; if(w) fa[w] = y;
    	up(y);
    }
    
    void splay(int x){while(nroot(x)){if(nroot(fa[x])) rot(son(x) == son(fa[x]) ? fa[x] : x); rot(x);} up(x);}
    void access(int x){
    	for(int y = 0 ; x ; y = x , x = fa[x]){
    		splay(x); vir[x] = vir[x] - sz[y] + sz[ch[x][1]];
    		ch[x][1] = y; up(x);
    	}
    }
    int fdrt(int x){access(x); splay(x); while(ch[x][0]) x = ch[x][0]; splay(x); return x;}
    void link(int x){splay(x); int y = fa[x] = pre[x]; access(y); splay(y); vir[y] += sz[x]; up(y);}
    void cut(int x){access(x); splay(x); ch[x][0] = fa[ch[x][0]] = 0; up(x);}
    int qry(int x){x += col[x] * N; access(x); splay(x); splay(x = fdrt(x)); return sz[ch[x][1]];}
    
    int main(){
    	N = read();
    	for(int i = 1 ; i < N ; ++i){int a = read() , b = read(); addEd(a , b); addEd(b , a);}
    	dfs(1 , 0); pre[1] = ++N;
    	for(int i = 1 ; i <= 2 * N ; ++i) sz[i] = 1;
    	for(int i = 1 ; i < N ; ++i){link(i); pre[i + N] = pre[i] + N;}
    	for(M = read() ; M ; --M)
    		if(read()){int id = read(); cut(id + N * col[id]); link(id + N * (col[id] ^= 1));}
    		else printf("%d
    " , qry(read()));
    	return 0;
    }
    

    Qtree7

    考虑在Qtree6的基础上支持子树最值。

    考虑维护所有虚子树的最大值,但是注意到我们还可能进行虚实转换使得虚子树变成实子树、不对当前点的虚子树max产生贡献,那么就不能够只使用一个标记维护max。

    考虑使用multiset维护一个点的虚子树的max构成的集合,那么在虚实更换的时候对这个multiset进行插入、删除即可进行更新。

    复杂度(O(qlog^2n))

    #include<bits/stdc++.h>
    using namespace std;
    
    int read(){
    	int a = 0; char c = getchar(); bool f = 0;
    	while(!isdigit(c)){f = c == '-'; c = getchar();}
    	while(isdigit(c)){
    		a = a * 10 + c - 48; c = getchar();
    	}
    	return f ? -a : a;
    }
    
    const int _ = 2e5 + 7;
    struct Edge{int end , upEd;}Ed[_ << 1];
    int head[_] , N , cntEd , pre[_] , col[_];
    
    void addEd(int a , int b){Ed[++cntEd] = (Edge){b , head[a]}; head[a] = cntEd;}
    void dfs(int x , int p){pre[x] = p; for(int i = head[x] ; i ; i = Ed[i].upEd) if(Ed[i].end != p) dfs(Ed[i].end , x);}
    
    int fa[_] , ch[_][2] , val[_] , mx[_]; multiset < int > vir[_];
    
    bool nroot(int x){return ch[fa[x]][0] == x || ch[fa[x]][1] == x;}
    bool son(int x){return ch[fa[x]][1] == x;}
    void up(int x){mx[x] = max(max(val[x] , vir[x].size() ? *--vir[x].end() : (int)-2e9) , max(mx[ch[x][0]] , mx[ch[x][1]]));}
    
    void rot(int x){
    	bool f = son(x); int y = fa[x] , z = fa[y] , w = ch[x][f ^ 1];
    	fa[x] = z; if(nroot(y)) ch[z][son(y)] = x;
    	fa[y] = x; ch[x][f ^ 1] = y;
    	ch[y][f] = w; if(w) fa[w] = y;
    	up(y);
    }
    
    void splay(int x){while(nroot(x)){if(nroot(fa[x])) rot(son(x) == son(fa[x]) ? fa[x] : x); rot(x);} up(x);}
    
    void access(int x){
    	for(int y = 0 ; x ; y = x , x = fa[x]){
    		splay(x); if(ch[x][1]) vir[x].insert(mx[ch[x][1]]);
    		if(y) vir[x].erase(vir[x].find(mx[y]));
    		ch[x][1] = y; up(x);
    	}
    }
    
    int fdrt(int x){access(x); splay(x); while(ch[x][0]) x = ch[x][0]; splay(x); return x;}
    void link(int x){splay(x); int t = pre[x]; access(t); splay(t); fa[x] = t; vir[t].insert(mx[x]); up(t);}
    void cut(int x){access(x); splay(x); ch[x][0] = fa[ch[x][0]] = 0; up(x);}
    void mdy(int x , int w){access(x); splay(x); val[x] = w; up(x);}
    int qry(int x){access(x); splay(x); x = fdrt(x); return mx[ch[x][1]];}
    
    int main(){
    	mx[0] = -2e9; N = read();
    	for(int i = 1 ; i < N ; ++i){int a = read() , b = read(); addEd(a , b); addEd(b , a);}
    	dfs(1 , 0); pre[1] = ++N;
    	for(int i = 1 ; i < N ; ++i) col[i] = read();
    	for(int i = 1 ; i < N ; ++i) val[i] = val[i + N] = mx[i] = mx[i + N] = read();
    	for(int i = 1 ; i < N ; ++i) pre[i + N] = pre[i] + N;
    	for(int i = 1 ; i < N ; ++i) link(i + col[i] * N);
    	for(int M = read() ; M ; --M){
    		int tp = read() , u = read();
    		if(tp == 0) printf("%d
    " , qry(u + col[u] * N));
    		else if(tp == 1){cut(u + col[u] * N); link(u + (col[u] ^= 1) * N);}
    		else{int w = read(); mdy(u , w); mdy(u + N , w);}
    	}
    	return 0;
    }
    
  • 相关阅读:
    C# 操作配置文件
    C# Excel操作类
    没有找到 mspdb100.dll 的解决办法
    工厂方法模式
    .Net互操作2
    The certificate used to sign “AppName” has either expired or has been revoked. An updated certificate is required to sign and install the application解决
    手机抓包xcode自带命令行工具配合wireshark实现
    expecting SSH2_MSG_KEX_ECDH_REPLY ssh_dispatch_run_fatal问题解决
    使用ssh-keygen设置ssh无密码登录
    远程复制文件到服务器
  • 原文地址:https://www.cnblogs.com/Itst/p/11341085.html
Copyright © 2011-2022 走看看