[BZOJ 3637]Query on a tree VI
偶然看见了这题,觉得自己 QTREE、COT 什么的都没有刷过的真是弱爆了……
一道思路很巧妙的题,终于是在约大爷的耐心教导下会了,真是太感谢约大爷了。
这题显然是树链剖分,但是链上维护的东西很恶心。其核心思想是找到一个相连的最浅同色节点,那么我只要维护每个点的子树中与他相连的点的数量即可
用 f[c][u] 表示在 u 的子树中与 u 相连 (假设 u 无色) 且颜色为 c 的点数
查询直接算出与 u 相连的最浅同色节点 a,ans=f[c[u]][a]
考虑修改,我们发现每次 u 被反转,影响到的点是 father[u] 一直往上,直到根或一个异色点(PS. 最浅异色 a 的 f[ ][a] 也会被改),而且他们的 f[][] 都是加一个数或减一个数
(PS2. father[u] 的 f[][] 会被改两次,因为 u 的颜色变了,导致 f[0][father[u]]、f[1][father[u]] 都在变)
区间修改,单点查询,于是用树状树组搞搞救过了
至于找到一个相连的最浅同色节点,可用线段树——比如:三叉神经树的做法
也可以在每条链上暴力挂 3 个 map 神马的……
反正是好 YY de 啦~
- #include <cstdio>
- #include <cstring>
- const int sizeOfPoint=;
- inline int getint();
- inline void putint(int);
- int n, m;
- int f[sizeOfPoint], d[sizeOfPoint], s[sizeOfPoint];
- int p[][sizeOfPoint];
- int num, idx[sizeOfPoint], son[sizeOfPoint], top[sizeOfPoint];
- bool c[sizeOfPoint];
- struct node
- {
- int ll, rr;
- bool lc, rc;
- int len;
- node * l, * r;
- inline void maintain();
- };
- node * t;
- node memory_node[sizeOfPoint<<], * port_node=memory_node;
- inline node * newnode(int, int);
- node * build(int, int);
- void update(node * , int);
- int query(node * , int, int);
- int sum[][sizeOfPoint];
- inline int lowbit(int);
- inline void update(int * , int, int, int);
- inline int query(int * , int);
- struct edge {int point; edge * next;};
- edge memory_edge[sizeOfPoint<<], * port_edge=memory_edge;
- edge * e[sizeOfPoint];
- inline edge * newedge(int, edge * );
- inline void link(int, int);
- inline int lg(int);
- void dfs_tree(int);
- void dfs_chain(int, int);
- inline int anc(int, int);
- inline void update(bool, int, int, int);
- inline int query(int);
- int main()
- {
- n=getint();
- for (int i=;i<n;i++)
- {
- int u=getint(), v=getint();
- link(u, v);
- }
- memset(d, 0xFF, sizeof(d)); d[]=;
- dfs_tree();
- dfs_chain(, );
- t=build(, n);
- for (int i=;i<=n;i++) update(sum[], idx[i], idx[i], s[i]-);
- m=getint();
- for (int i=;i<=m;i++)
- {
- int o=getint(), u=getint();
- if (o==)
- {
- int f=query(u);
- putint(+query(sum[c[f]], idx[f]));
- }
- else if (u==) c[u]^=;
- else
- {
- int s=query(sum[c[u]], idx[u])+;
- c[u]^=;
- update(t, idx[u]);
- if (c[u]==c[f[u]])
- {
- update(sum[!c[u]], idx[f[u]], idx[f[u]], -s);
- int a=query(f[u]);
- s=query(sum[c[u]], idx[u])+;
- if (a==) update(c[u], f[u], a, s);
- else update(c[u], f[u], f[a], s);
- }
- else
- {
- int a=query(f[u]);
- if (a==) update(!c[u], f[u], a, -s);
- else update(!c[u], f[u], f[a], -s);
- s=query(sum[c[u]], idx[u])+;
- update(sum[c[u]], idx[f[u]], idx[f[u]], s);
- }
- }
- }
- return ;
- }
- inline int getint()
- {
- register int num=;
- register char ch;
- do ch=getchar(); while (ch<'' || ch>'');
- do num=num*+ch-'', ch=getchar(); while (ch>='' && ch<='');
- return num;
- }
- inline void putint(int num)
- {
- char stack[];
- register int top=;
- if (num==) stack[top=]='';
- for ( ;num;num/=) stack[++top]=num%+'';
- for ( ;top;top--) putchar(stack[top]);
- putchar('\n');
- }
- inline void node::maintain()
- {
- lc=l->lc; rc=r->rc;
- len=r->len;
- if (len==r->rr-r->ll+ && l->rc==r->lc) len+=l->len;
- }
- inline node * newnode(int ll, int rr)
- {
- node * ret=port_node++;
- ret->ll=ll; ret->rr=rr;
- ret->l=ret->r=NULL;
- return ret;
- }
- node * build(int ll, int rr)
- {
- node * t=newnode(ll, rr);
- if (ll==rr) t->lc=t->rc=c[ll], t->len=;
- else
- {
- int m=(ll+rr)>>;
- t->l=build(ll, m);
- t->r=build(m+, rr);
- t->maintain();
- }
- return t;
- }
- void update(node * t, int k)
- {
- if (t->ll==t->rr) t->lc=t->rc=c[t->ll];
- else
- {
- int m=(t->ll+t->rr)>>;
- if (k<=m) update(t->l, k);
- else update(t->r, k);
- t->maintain();
- }
- }
- int query(node * t, int ql, int qr)
- {
- int ret=;
- if (t->ll==ql && t->rr==qr) ret=t->len;
- else
- {
- int m=(t->ll+t->rr)>>;
- if (qr<=m) ret=query(t->l, ql, qr);
- else if (ql>m) ret=query(t->r, ql, qr);
- else
- {
- ret=query(t->r, m+, qr);
- if (ret==qr-m && t->r->lc==t->l->rc) ret+=query(t->l, ql, m);
- }
- }
- return ret;
- }
- inline int lowbit(int x)
- {
- return x & -x;
- }
- inline void update(int * c, int l, int r, int v)
- {
- for ( ;l<=n;l+=lowbit(l)) c[l]+=v;
- for (r++;r<=n;r+=lowbit(r)) c[r]-=v;
- }
- inline int query(int * c, int i)
- {
- int ret=;
- for ( ;i;i-=lowbit(i)) ret+=c[i];
- return ret;
- }
- inline edge * newedge(int point, edge * next)
- {
- edge * ret=port_edge++;
- ret->point=point; ret->next=next;
- return ret;
- }
- inline void link(int u, int v)
- {
- e[u]=newedge(v, e[u]); e[v]=newedge(u, e[v]);
- }
- inline int lg(int u)
- {
- return !u?:-__builtin_clz(u);
- }
- void dfs_tree(int u)
- {
- s[u]=;
- for (int i=;i<=lg(d[u]);i++) p[i][u]=p[i-][p[i-][u]];
- for (edge * i=e[u];i;i=i->next) if (d[i->point]==-)
- {
- f[i->point]=u; d[i->point]=d[u]+;
- dfs_tree(i->point);
- s[u]+=s[i->point];
- if (s[i->point]>s[son[u]])
- son[u]=i->point;
- }
- }
- void dfs_chain(int u, int top_u)
- {
- idx[u]=++num; top[u]=u;
- if (son[u]) dfs_chain(son[u], top_u);
- for (edge * i=e[u];i;i=i->next) if (!idx[i->point])
- dfs_chain(i->point, i->point);
- }
- inline int anc(int u, int k)
- {
- for (int i=;i>=;i--)
- if ((k>>i)&)
- u=p[k][u];
- return u;
- }
- inline void update(bool c, int u, int v, int s)
- {
- while (top[u]!=top[v])
- {
- update(sum[c], idx[top[u]], idx[u], s);
- u=f[top[u]];
- }
- update(sum[c], idx[v], idx[u], s);
- }
- inline int query(int u)
- {
- for ( ; ; )
- {
- int l=query(t, idx[top[u]], idx[u]);
- if (l==d[top[u]]-d[u]+)
- {
- if (top[u]==) return ;
- if (c[top[u]]==c[f[top[u]]]) u=f[top[u]];
- else return top[u];
- }
- else
- return anc(u, l-);
- }
- }
解锁新成就:rank last
[BZOJ 3637]Query on a tree VI的更多相关文章
- bzoj 3637: Query on a tree VI 树链剖分 && AC600
3637: Query on a tree VI Time Limit: 8 Sec Memory Limit: 1024 MBSubmit: 206 Solved: 38[Submit][Sta ...
- BZOJ 3637: Query on a tree VI LCT_维护子树信息_点权转边权_好题
非常喜欢这道题. 点权转边权,这样每次在切断一个点的所有儿子的时候只断掉一条边即可. Code: #include <cstring> #include <cstdio> #i ...
- QTREE6 - Query on a tree VI 解题报告
QTREE6 - Query on a tree VI 题目描述 给你一棵\(n\)个点的树,编号\(1\)~\(n\).每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我 ...
- bzoj3637: Query on a tree VI
Description You are given a tree (an acyclic undirected connected graph) with n nodes. The tree node ...
- BZOJ3637 Query on a tree VI(树链剖分+线段树)
考虑对于每一个点维护子树内与其连通的点的信息.为了换色需要,记录每个点黑白两种情况下子树内连通块的大小. 查询时,找到深度最浅的同色祖先即可,这可以比较简单的树剖+线段树乱搞一下(似乎就是qtree3 ...
- SPOJ QTREE Query on a tree VI
You are given a tree (an acyclic undirected connected graph) with n nodes. The tree nodes are number ...
- BZOJ 3639: Query on a tree VII
Description 一棵树,支持三种操作,修改点权,修改颜色,问所有与他路径上颜色相同的点的最大权,包含这两个点. Sol LCT. 用LCT来维护重边,对于每个节点在建一个set用来维护轻边,这 ...
- QTREE6&&7 - Query on a tree VI &&VII
树上连通块 不用具体距离,只询问连通块大小或者最大权值 可以类比Qtree5的方法,但是记录东西很多,例如子树有无0/1颜色等 一个trick,两个LCT分离颜色 每个颜色在边上. 仅保留连通块顶部不 ...
- 2019.02.17 spoj Query on a tree VI(链分治)
传送门 题意简述:给你一棵nnn个黑白点的树,支持改一个点的颜色,询问跟某个点颜色相同的连通块大小. 思路: 还是链分治 233 记fi,0/1f_{i,0/1}fi,0/1表示iii的所有颜色为0 ...
随机推荐
- Maven联网问题
关于Maven联网问题 关于如何找到Maven默认的本地仓库问题 修改Maven默认本地仓库 找到 <localRepository>/path/to/local/repo</loc ...
- sqlserverdriver配置方法 jdbc连接sqlserver
一.下载驱动程序. 下载地址:http://download.microsoft.com/download/8/B/D/8BDABAE2-B6EA-41D4-B903-7916EF3690EF/sql ...
- apicloud 解析
function jiexi(id) { var getTabBarActivityUrl = '/QuestionReport?filter='; var urlParam = {}; ajaxRe ...
- ASP.net页面代码执行顺序
<%=TextBox1 .Text%> <asp:TextBox ID="TextBox1" runat="server">abc< ...
- [转载 ]POJ 1273 最大流模板
转载 百度文库花了5分下的 不过确实是自己需要的东西经典的最大流题POJ1273 ——其他练习题 POJ3436 . 题意描述: 现在有m个池塘(从1到m开始编号,1为源点,m为汇点),及n条水渠,给 ...
- DOM事件简介--摘自admin10000
Click.touch.load.drag.change.input.error.risize — 这些都是冗长的DOM(文档对象模型)事件列表的一部分.事件可以在文档(Document)结构的任何部 ...
- React Native工作小技巧及填坑记录
以下是本人在React Native开发工作中使用的一些小技巧,记录一下. 1.从网络上拉取下来的React Native缺少React和React Native库. 终端 1. cd 项目根目录 2 ...
- Golang游戏服务器
我对和GOLANG写MMO服务器的一些遐想: 1.沙盒(隔离性) SKYNET:原生LUA STATE作为沙盒, 进行服务器间隔离安全性高: 服务可以很容易的配置到不同节点之上. GO:估计用RECO ...
- sql语句变量定义和样例
变量和与常量 1.定义和使用局部变量说明:局部变量是用户可自定义的变量,它的作用范围仅在程序内部.局部变量的名称是用户自定义的,命名的局部变量名要符合SQL Server 2000标识符命名规则,必须 ...
- Linux自己安装redis扩展
注意:目录的权限 chomd 777 -R 注意:下面涉及的目录只是我自己安装的目录,要找自己对应的目录文件 1.安装redis 下载:https://github.com/nicolasff/p ...