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;
    }
    
  • 相关阅读:
    svn-Subversion
    英语学习-2020年4月
    自动化-研究
    数据库-存储过程
    未来软件测试的发展趋势
    学习alex---人生导师
    自动化测试-----总结
    接口测试总结
    jmeter-接口测试项目
    接口测试jmeter
  • 原文地址:https://www.cnblogs.com/Itst/p/11341085.html
Copyright © 2011-2022 走看看