bzoj 4817: [Sdoi2017]树点涂色 LCT+树链剖分+线段树
2017-04-14 20:58
239 查看
题目:
Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同.
定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。
Bob可能会进行这几种操作:
1 x: 把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
2 x y: 求x到y的路径的权值。
3 x y: 在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
1<=n,m<=100000
题解:
这道题就是重组病毒的弱化版.
要是HE省选也考这种我会的题目超级弱化版就好了
跟重组病毒一样,我们发现第一个操作其实就是把一条链到根的颜色变得相同了.
如果我们用一条连向fa的虚边表示这个点的颜色和父亲的节点的颜色不同
反之,实边表示相同.那么如果求两点路径权值就是求路径上虚边的个数+1(因lca未被统计)
然后我们发现第一个操作其实就是Access.
然后外部进行树链剖分,在LCT Access的切断和连接实边的时候更新外部数据结构即可.
2,3两个操作都可以分别维护.
对于操作2 : 若某点连向fa为虚边对单点赋值为1,否则为0.然后直接跳top统计即可.
对于操作3 : 对每个点维护一个这个点到根的路径权,每次若连向fa的边改变,做区间修改即可,查询即区间最值.
代码比重组病毒好写多了
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; inline void read(int &x){ x=0;static char ch;static bool flag;flag = false; while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true; while(x=(x<<1)+(x<<3)+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x; } #define rg register int #define rep(i,a,b) for(rg i=(a);i<=(b);++i) #define per(i,a,b) for(rg i=(a);i>=(b);--i) const int maxn = 100010; struct Edge{ int to,next; }G[maxn<<1]; int head[maxn],cnt; void add(int u,int v){ G[++cnt].to = v; G[cnt].next = head[u]; head[u] = cnt; } int n,m; namespace seg{ #define v G[i].to int top[maxn],son[maxn],siz[maxn]; int dep[maxn],ind[maxn],oud[maxn]; int dfs_clock,fa[maxn]; void dfs(int u){ siz[u] = 1; for(int i = head[u];i;i=G[i].next){ if(v == fa[u]) continue; fa[v] = u; dep[v] = dep[u] + 1; dfs(v); siz[u] += siz[v]; if(siz[son[u]] < siz[v]) son[u] = v; } } void dfs(int u,int tp){ top[u] = tp; ind[u] = ++ dfs_clock; if(son[u]) dfs(son[u],tp); for(int i = head[u];i;i=G[i].next){ if(v == fa[u] || v == son[u]) continue; dfs(v,v); } oud[u] = dfs_clock; } #undef v struct segTree{ int sum[maxn<<2],tag[maxn<<2],mx[maxn<<2]; inline void pushdown(int rt,int l,int r){ if(rt == 0 || tag[rt] == 0) return ; int mid = l+r >> 1; sum[rt<<1] += tag[rt]*(mid - l + 1); sum[rt<<1|1] += tag[rt]*(r - mid); mx[rt<<1] += tag[rt]; mx[rt<<1|1] += tag[rt]; tag[rt<<1] += tag[rt]; tag[rt<<1|1] += tag[rt]; tag[rt] = 0; } void modify(int rt,int l,int r,int L,int R,int d){ if(L <= l && r <= R){ tag[rt] += d; sum[rt] += d*(r - l + 1); mx[rt] += d; return ; } int mid = l+r >> 1;pushdown(rt,l,r); if(L <= mid) modify(rt<<1,l,mid,L,R,d); if(R > mid) modify(rt<<1|1,mid+1,r,L,R,d); sum[rt] = sum[rt<<1] + sum[rt<<1|1]; mx[rt] = max(mx[rt<<1],mx[rt<<1|1]); } int query_max(int rt,int l,int r,int L,int R){ if(L <= l && r <= R) return mx[rt]; int mid = l+r >> 1;pushdown(rt,l,r); if(R <= mid) return query_max(rt<<1,l,mid,L,R); if(L > mid) return query_max(rt<<1|1,mid+1,r,L,R); return max(query_max(rt<<1,l,mid,L,R),query_max(rt<<1|1,mid+1,r,L,R)); } int query_sum(int rt,int l,int r,int L,int R){ if(L <= l && r <= R) return sum[rt]; int mid = l+r >> 1;pushdown(rt,l,r); if(R <= mid) return query_sum(rt<<1,l,mid,L,R); if(L > mid) return query_sum(rt<<1|1,mid+1,r,L,R); return query_sum(rt<<1,l,mid,L,R) + query_sum(rt<<1|1,mid+1,r,L,R); } }T1,T2; } namespace lct{ using namespace seg; struct Node{ Node *ch[2],*fa; int id; }mem[maxn],*it,*null; inline void init(){ it = mem;null = it++; null->ch[0] = null->ch[1] = null->fa = null; null->id = -1; } inline Node* newNode(){ Node *p = it++; p->ch[0] = p->ch[1] = p->fa = null; return p; } inline void rotate(Node *p,Node *x){ int k = p == x->ch[1]; Node *y = p->ch[k^1],*z = x->fa; if(z->ch[0] == x) z->ch[0] = p; if(z->ch[1] == x) z->ch[1] = p; if(y != null) y->fa = x; p->ch[k^1] = x;p->fa = z; x->ch[k] = y;x->fa = p; } inline bool isroot(Node *p){ return (p == null) || (p->fa->ch[0] != p && p->fa->ch[1] != p); } inline void Splay(Node *p){ while(!isroot(p)){ Node *x = p->fa,*y = x->fa; if(isroot(x)) rotate(p,x); else if((p == x->ch[0])^(x == y->ch[0])) rotate(p,x),rotate(p,y); else rotate(x,y),rotate(p,x); } } inline void Access(Node *x){ for(Node *y = null;x != null;y = x,x = x->fa){ Splay(x); Node *p = x->ch[1]; while(p->ch[0] != null) p = p->ch[0]; if(p != null){ T1.modify(1,1,n,ind[p->id],ind[p->id],1); T2.modify(1,1,n,ind[p->id],oud[p->id],1); } p = y; while(p->ch[0] != null) p = p->ch[0]; if(p != null){ T1.modify(1,1,n,ind[p->id],ind[p->id],-1); T2.modify(1,1,n,ind[p->id],oud[p->id],-1); } x->ch[1] = y; } } } inline int query(int u,int v){ using namespace seg; int ret = 0; while(top[u] != top[v]){ if(dep[top[u]] < dep[top[v]]) swap(u,v); ret += T1.query_sum(1,1,n,ind[top[u]],ind[u]); u = fa[top[u]]; }if(dep[u] > dep[v]) swap(u,v); if(ind[u] + 1 <= ind[v]) ret += T1.query_sum(1,1,n,ind[u]+1,ind[v]); return ret; } int main(){ using namespace lct; using namespace seg; read(n);read(m); init(); rep(i,1,n) newNode()->id = i; rg u,v; rep(i,1,n-1){ read(u);read(v); add(u,v);add(v,u); } dfs(1);dfs(1,1); rep(i,2,n){ T1.modify(1,1,n,ind[i],ind[i],1); T2.modify(1,1,n,ind[i],oud[i],1); (mem+i)->fa = (mem+fa[i]); } rg op; while(m--){ read(op); if(op == 1){ read(u); Access(mem+u); }else if(op == 2){ read(u);read(v); printf("%d\n",query(u,v)+1); }else if(op == 3){ read(u); printf("%d\n",T2.query_max(1,1,n,ind[u],oud[u])+1); } } return 0; }
相关文章推荐
- [SDOI2017][bzoj4817] 树点涂色 [LCT+线段树]
- BZOJ.4817.[SDOI2017]树点涂色(LCT DFS序 线段树)
- 【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]
- [LCT] BZOJ4817.[Sdoi2017]树点涂色
- BZOJ 4817 [Sdoi2017]树点涂色 ——LCT 线段树
- 【BZOJ4817】树点涂色(LCT,线段树,树链剖分)
- bzoj 4817: [Sdoi2017]树点涂色
- bzoj 4817: [Sdoi2017]树点涂色【树链剖分+LCT】
- 【BZOJ4817】树点涂色(LCT,线段树,树链剖分)
- BZOJ 4817: [Sdoi2017]树点涂色
- BZOJ 4817: [Sdoi2017]树点涂色(LCT+树剖+线段树)
- bzoj 4817: [Sdoi2017]树点涂色 link cut tree+线段树+树链剖分
- bzoj4817[Sdoi2017]树点涂色
- bzoj 4817: [Sdoi2017]树点涂色
- [BZOJ]4817: [Sdoi2017]树点涂色
- bzoj4817: [Sdoi2017]树点涂色
- AC日记——[SDOI2017]树点涂色 bzoj 4817
- 【XSY2534】【BZOJ4817】树点涂色 LCT 倍增 线段树 dfs序
- [bzoj4817][Sdoi2017]树点涂色
- 【BZOJ4821】[Sdoi2017]相关分析 线段树