【SDOI 2014】 旅行
【题目链接】
【算法】
树链剖分
每个宗教建一棵线段树,注意数据量大,要动态开点
【代码】
#include<bits/stdc++.h> using namespace std; #define MAXLOG 18 const int MAXN = 1e5 + 10; const int MAXS = 1e7 + 10; int i,n,q,x,y,t,Lca,SZ,timer; int w[MAXN],c[MAXN],son[MAXN],dfn[MAXN],top[MAXN],size[MAXN],anc[MAXN][MAXLOG], dep[MAXN],fa[MAXN],lc[MAXS],rc[MAXS],sum[MAXS],Max[MAXS],root[MAXN]; vector<int> e[MAXN]; char opt[5]; inline void dfs1(int x) { int i,y; anc[x][0] = fa[x]; for (i = 1; i < MAXLOG; i++) { if (dep[x] < (1 << i)) break; anc[x][i] = anc[anc[x][i-1]][i-1]; } size[x] = 1; for (i = 0; i < e[x].size(); i++) { y = e[x][i]; if (fa[x] != y) { dep[y] = dep[x] + 1; fa[y] = x; dfs1(y); size[x] += size[y]; if (size[y] > size[son[x]]) son[x] = y; } } } inline void dfs2(int x,int tp) { int i,y; dfn[x] = ++timer; top[x] = tp; if (son[x]) dfs2(son[x],tp); for (i = 0; i < e[x].size(); i++) { y = e[x][i]; if (fa[x] != y && son[x] != y) dfs2(y,y); } } inline int lca(int x,int y) { int i,t; if (dep[x] > dep[y]) swap(x,y); t = dep[y] - dep[x]; for (i = 0; i < MAXLOG; i++) { if (t & (1 << i)) y = anc[y][i]; } if (x == y) return x; for (i = MAXLOG - 1; i >= 0; i--) { if (anc[x][i] != anc[y][i]) { x = anc[x][i]; y = anc[y][i]; } } return fa[x]; } inline void push_up(int root) { Max[root] = max(Max[lc[root]],Max[rc[root]]); sum[root] = sum[lc[root]] + sum[rc[root]]; } inline void modify(int &root,int l,int r,int x,int val) { int mid; if (!root) root = ++SZ; if (l == r) { Max[root] = sum[root] = val; return; } mid = (l + r) >> 1; if (mid >= x) modify(lc[root],l,mid,x,val); else modify(rc[root],mid+1,r,x,val); push_up(root); } inline int query_max(int root,int l,int r,int ql,int qr) { int mid; if (!root) return 0; if (l == ql && r == qr) return Max[root]; mid = (l + r) >> 1; if (mid >= qr) return query_max(lc[root],l,mid,ql,qr); else if (mid + 1 <= ql) return query_max(rc[root],mid+1,r,ql,qr); else return max(query_max(lc[root],l,mid,ql,mid),query_max(rc[root],mid+1,r,mid+1,qr)); } inline int query_sum(int root,int l,int r,int ql,int qr) { int mid; if (!root) return 0; if (l == ql && r == qr) return sum[root]; mid = (l + r) >> 1; if (mid >= qr) return query_sum(lc[root],l,mid,ql,qr); else if (mid + 1 <= ql) return query_sum(rc[root],mid+1,r,ql,qr); else return query_sum(lc[root],l,mid,ql,mid) + query_sum(rc[root],mid+1,r,mid+1,qr); } inline int solve1(int c,int x,int y) { int ans = 0, tx = top[x],ty = top[y]; while (tx != ty) { ans = max(ans,query_max(root[c],1,n,dfn[tx],dfn[x])); x = fa[tx]; tx = top[x]; } ans = max(ans,query_max(root[c],1,n,dfn[y],dfn[x])); return ans; } inline int solve2(int c,int x,int y) { int ans = 0, tx = top[x],ty = top[y]; while (tx != ty) { ans += query_sum(root[c],1,n,dfn[tx],dfn[x]); x = fa[tx]; tx = top[x]; } ans += query_sum(root[c],1,n,dfn[y],dfn[x]); return ans; } int main() { scanf("%d%d",&n,&q); for (i = 1; i <= n; i++) scanf("%d%d",&w[i],&c[i]); for (i = 1; i < n; i++) { scanf("%d%d",&x,&y); e[x].push_back(y); e[y].push_back(x); } dfs1(1); dfs2(1,1); for (i = 1; i <= n; i++) modify(root[c[i]],1,n,dfn[i],w[i]); while (q--) { scanf("%s",&opt); if (strcmp(opt,"CC") == 0) { scanf("%d%d",&x,&y); modify(root[c[x]],1,n,dfn[x],0); c[x] = y; modify(root[c[x]],1,n,dfn[x],w[x]); } if (strcmp(opt,"CW") == 0) { scanf("%d%d",&x,&y); modify(root[c[x]],1,n,dfn[x],y); w[x] = y; } if (strcmp(opt,"QS") == 0) { scanf("%d%d",&x,&y); Lca = lca(x,y); t = solve2(c[x],x,Lca) + solve2(c[x],y,Lca); if (c[Lca] == c[x]) t -= w[Lca]; printf("%d\n",t); } if (strcmp(opt,"QM") == 0) { scanf("%d%d",&x,&y); Lca = lca(x,y); printf("%d\n",max(solve1(c[x],x,Lca),solve1(c[x],y,Lca))); } } return 0; }