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("\n" , 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);elsechange(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);elsechange(1 , cmp(start[a << 1] , start[(a << 1) - 1]) , b);}}return 0;
}

Qtree2

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

    #include<bits/stdc++.h>//This code is written by Itstusing 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\n" , LCA(read() , read()).second);break;case 'T':a = read();b = read();c = read();printf("%d\n" , 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);elsechange(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('\n');}}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\n" , query(read()));elsemodify(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\n" , 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\n" , 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;
}

转载于:https://www.cnblogs.com/Itst/p/11341085.html

SPOJ Qtree系列相关推荐

  1. SPOJ QTREE

    QTREE /*题目大意:维护一棵树,允许修改边权以及查询链上最大值题解:我们将边权转为点权,标记在深度较深的点上,树链剖分后用线段树处理即可 */ #include <cstdio> # ...

  2. SPOJ QTree【树链剖分】

    一 题目 QTREE 二 分析 第一道树链剖分的题,写的好艰难啊. 题意还是比较好理解的,就是在树上操作. 对于修改,题中要求的是单点修改,就算是直接树上操作也是非常简单的. 对于查询,查询的时候,是 ...

  3. 【高级数据结构】[SPOJ QTREE]树链剖分/动态树各一模板

    题目: 树链剖分: #include<cstdio> #include<cstring> #include<algorithm> using namespace s ...

  4. SPOJ - QTREE Query on a tree(树链剖分+线段树)

    题目链接:点击查看 题目大意:给出一棵由n个点组成的树,再给出数个操作,每次操作分为下列几种类型: QUERY x y:询问点x-点y这条路径上的所有边权的最大值 CHANGE x y:将第x条边的权 ...

  5. QTREE系列1,4,5,6,7 LCT

    QTREE1 题意: 给出一棵N(N <= 10000)个点的树,要求支持: 1.改变第i条边的权值 2.求a->b上的最大边权 解: 直接树剖或LCT即可 代码 1.LCT(660ms) ...

  6. spoj 2398 Qtree3

    Description 给出一棵树,树节点的颜色初始时为白色,有两种操作: 0 x:把x号节点颜色取反 1 x:询问1到x路径上第一个黑点编号 Solution 最近想练练剖分和线段树,于是想到来做做 ...

  7. [kuangbin]各种各样的题单

    [kuangbin]各种各样的题单 专题1 简单搜索 POJ 1321 POJ 2251 POJ 3278 POJ 3279 POJ 1426 POJ 3126 POJ 3087 POJ 3414 F ...

  8. 树链剖分入门——[kuangbin]树链剖分

    树链剖分的本质就是将一棵树拆分成一段一段连续的区间,然后放在一起就可以用一棵单独的线段树处理区间问题,只需要将树上节点和线段树节点的对应关系求好就可以很方便的互相转换,而树上两点之间路径的相关问题就可 ...

  9. SPOJ Can you answer the Queries系列

    GSS1 线段树最大子段和裸题,不带修改,注意pushup. 然而并不会猫树之类的东西 1 #include<bits/stdc++.h> 2 #define MAXN 50001 3 u ...

  10. 【Qtree】Query on a tree系列LCT解法

    Qtree1-7 Qtree1 裸的树链剖分,当然也可以用LCT写,就不说什么了... Qtree2 倍增lca,当然也可以用LCT写,就不说什么了... Qtree3 裸的树链剖分,当然也可以用LC ...

最新文章

  1. seaborn箱图(box plot)可视化、并且在箱图中使用三角形标注均值的位置(showmeans=True)
  2. Tomcat双向Https验证搭建,亲自实现与主流浏览器、Android/iOS移动客户端超安全通信
  3. 一文看懂Java微服务架构,WEB2.0,垂直架构,分布式架构,微服务架构
  4. 详解|清华大学100页PPT:工业机器人技术详解
  5. 有人质疑面向对象编程?
  6. 牛客 - 牛牛的最大兴趣组(思维+数论)
  7. u-boot的Makefile分析
  8. 阿昌教你Linux密码忘记后如何重置
  9. 如何建立能力评估模型?
  10. Windows10系统迁移-同一PC硬盘之间
  11. 什么是数据库的存储过程?
  12. pycharm的安装,简单使用
  13. ERD(实体关系图)概念了解
  14. mermaid 饼图使用指南
  15. cs224w(图机器学习)2021冬季课程学习笔记15 Frequent Subgraph Mining with GNNs
  16. 面向对像(8day) 正则表达式,日志格式,json模块
  17. 高中计算机教室标语,高中班级教室励志标语
  18. ubuntu中snap包的安装、更新删除与简单使用
  19. P1577切绳子问题
  20. Android】中微信抢红包助手的实现(代码整理)

热门文章

  1. 纪念一下我这尴尬中二的排名吧
  2. SQLServer数据库增、删、改、查简单操作示例
  3. R语言各个包里面的数据集
  4. 以上是对图像的椒盐噪声处理,在p_temp[j*wide+i]=0;这句程序中为什么要乘以wide,求解,谢谢!
  5. 为什么交叉熵损失函数可以用作逻辑回归的损失函数?
  6. mysql php sdk_PHP连接MySQL数据库
  7. 动态规划之状态压缩DP
  8. 2020-06-28
  9. c语言测试1到3章,c语言谭浩强第1章至第3章测试试题
  10. 51单片机mysql_[学习笔记]15个QA让你快速入门51单片机开发