[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 ...
随机推荐
- 关于<form>标签
<form>用于为用户输入创建HTML表单,表单用于向服务器传输数据 form是块级元素,其前后会产生折行 <form>包含: 1.input元素:(根据不同的type属性,输 ...
- mariadb配置允许远程访问方式
首先配置允许访问的用户,采用授权的方式给用户权限 1 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'IDENTIFIED BY '123456' WITH GRAN ...
- 第K大数
控制数据箱(box.c/cpp/pas)[题目大意]现在给你一个数据箱,支持以下操作,加入元素,第 n次查询操作求当前情况下的第 n 大数.比如说,第 3 次查询操作求第三小的数.当然查询操作的给出方 ...
- 第二章 XHTML 基础
元素与标签术语,HTML/XHTMLXHTML之间的联系区别在XHTML中,所有元素之间必须完成正确的嵌套,元素必须是闭合的,必须小写.必须有个跟元素HTML. 标题标<h1>语法:< ...
- fatal: Could not read from remote repository.的解决办法
1. git remote –v查看远端地址或者查看配置 git config –list 2. git status 3. git add . git status git commit -m “本 ...
- Linux (centos )下Nginx+PHP+MySQL配置——自己的lnmp配置
说明:所有软件都是从官网上下载最新版的stable版本 ##################### 获取最新源码包###################### #建立独立的webserver#mkdi ...
- 关于easyui遇到的问题
easyui中的datagrid分页中有时候会碰到context.Request["rows"]的值等于nAn的问题:这是一般都是设置的pageSize的值不在pageList里引 ...
- Caffe 源碼閱讀(五) Solver.cpp
1.Solver类两个构造函数 Solver(const SolverParameter& param) Solver(const string& param_file) 初始化两个类 ...
- iOS给UIimage添加圆角的两种方式
众所周知,给图片添加圆角有CALayer的cornerRadius, 比如: 最直接的方法: imgView.layer.cornerRadius1=110; imgView.clipsToBou ...
- Jquery.Form和jquery.validate 的使用
有些功能需要我们利用Ajax技术进行POST提交表单,这时候就需要用到jquery.Form ,它有两种方式进行提交, AjaxForm和AjaxSubmit方式. AjaxFo ...