BZOJ4817: [Sdoi2017]树点涂色(LCT)
Description
Input
Output
Sample Input
1 2
2 3
3 4
3 5
2 4 5
3 3
1 4
2 4 5
1 5
2 4 5
Sample Output
4
2
2
解题思路:
LCT好题access构造。
将第一个操作视为access操作并更新答案。
那么开始时视为没有轻重链。
access过程中若发生轻重链转化时将子树答案都加1,并撤销上一节点操作。
这样就可以在每一个节点上维护到根的权值和。
第三问直接解决。
第二问呢,发现合并两条链的代价就是两个链单独的代价-2*lca代价+1(因为lca节点需要考虑)
子树修改普通Dfs就好了。
代码:
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #define lll tr[spc].ch[0]
- #define rrr tr[spc].ch[1]
- #define ls ch[0]
- #define rs ch[1]
- typedef long long lnt;
- const int N=;
- struct seg_trnt{
- int lzt;
- int maxval;
- }ter[N<<];
- struct spl_trnt{
- int ch[];
- int fa;
- int lzt;
- bool anc;
- }tr[N];
- struct pnt{
- int hd;
- int dp;
- int ind;
- int oud;
- int fa[];
- }p[N];
- struct ent{
- int twd;
- int lst;
- }e[N<<];
- int n,m;
- int cnt;
- int dfn;
- bool sta=true;
- int pos[N];
- void pushup(int spc)
- {
- ter[spc].maxval=std::max(ter[spc<<].maxval,ter[spc<<|].maxval);
- return ;
- }
- void ppushdown(int spc)
- {
- if(ter[spc].lzt)
- {
- ter[spc<<].maxval+=ter[spc].lzt;
- ter[spc<<|].maxval+=ter[spc].lzt;
- ter[spc<<].lzt+=ter[spc].lzt;
- ter[spc<<|].lzt+=ter[spc].lzt;
- ter[spc].lzt=;
- }
- return ;
- }
- void update(int l,int r,int ll,int rr,int spc,int v)
- {
- if(ll>r||l>rr)
- return ;
- if(ll<=l&&r<=rr)
- {
- ter[spc].maxval+=v;
- ter[spc].lzt+=v;
- return ;
- }
- ppushdown(spc);
- int mid=(l+r)>>;
- update(l,mid,ll,rr,spc<<,v);
- update(mid+,r,ll,rr,spc<<|,v);
- pushup(spc);
- return ;
- }
- int maxq(int l,int r,int ll,int rr,int spc)
- {
- if(ll>r||l>rr)
- return -0x3f3f3f3f;
- if(ll<=l&&r<=rr)
- return ter[spc].maxval;
- int mid=(l+r)>>;
- ppushdown(spc);
- return std::max(maxq(l,mid,ll,rr,spc<<),maxq(mid+,r,ll,rr,spc<<|));
- }
- int query(int l,int r,int pos,int spc)
- {
- if(l==r)
- return ter[spc].maxval;
- ppushdown(spc);
- int mid=(l+r)>>;
- if(pos<=mid)
- return query(l,mid,pos,spc<<);
- return query(mid+,r,pos,spc<<|);
- }
- void build(int l,int r,int spc)
- {
- if(l==r)
- {
- ter[spc].maxval=p[pos[l]].dp;
- return ;
- }
- int mid=(l+r)>>;
- build(l,mid,spc<<);
- build(mid+,r,spc<<|);
- pushup(spc);
- return ;
- }
- void ade(int f,int t)
- {
- cnt++;
- e[cnt].twd=t;
- e[cnt].lst=p[f].hd;
- p[f].hd=cnt;
- return ;
- }
- void dfs(int x,int f)
- {
- p[x].dp=p[f].dp+;
- p[x].fa[]=f;
- pos[++dfn]=x;
- p[x].ind=dfn;
- for(int i=;i<=;i++)
- p[x].fa[i]=p[p[x].fa[i-]].fa[i-];
- for(int i=p[x].hd;i;i=e[i].lst)
- {
- int to=e[i].twd;
- if(to==f)
- continue;
- tr[to].fa=x;
- dfs(to,x);
- }
- p[x].oud=dfn;
- return ;
- }
- int Lca(int x,int y)
- {
- if(p[x].dp<p[y].dp)
- std::swap(x,y);
- for(int i=;i>=;i--)
- {
- if(p[p[x].fa[i]].dp>=p[y].dp)
- x=p[x].fa[i];
- }
- if(x==y)
- return x;
- for(int i=;i>=;i--)
- {
- if(p[x].fa[i]!=p[y].fa[i])
- x=p[x].fa[i],y=p[y].fa[i];
- }
- return p[x].fa[];
- }
- bool whc(int spc)
- {
- return tr[tr[spc].fa].rs==spc;
- }
- void trr(int spc)
- {
- if(!spc)
- return ;
- std::swap(lll,rrr);
- tr[spc].lzt^=;
- return ;
- }
- void pushdown(int spc)
- {
- if(tr[spc].lzt)
- {
- tr[spc].lzt=;
- trr(lll);
- trr(rrr);
- }
- return ;
- }
- void recal(int spc)
- {
- if(!tr[spc].anc)
- recal(tr[spc].fa);
- pushdown(spc);
- return ;
- }
- void rotate(int spc)
- {
- int f=tr[spc].fa;
- bool k=whc(spc);
- tr[f].ch[k]=tr[spc].ch[!k];
- tr[spc].ch[!k]=f;
- if(tr[f].anc)
- {
- tr[f].anc=;
- tr[spc].anc=;
- }else
- tr[tr[f].fa].ch[whc(f)]=spc;
- tr[spc].fa=tr[f].fa;
- tr[f].fa=spc;
- tr[tr[f].ch[k]].fa=f;
- return ;
- }
- void splay(int spc)
- {
- recal(spc);
- while(!tr[spc].anc)
- {
- int f=tr[spc].fa;
- if(tr[f].anc)
- {
- rotate(spc);
- return ;
- }
- if(whc(spc)^whc(f))
- rotate(spc);
- else
- rotate(f);
- rotate(spc);
- }
- return ;
- }
- int leftpos(int spc)
- {
- pushdown(spc);
- while(lll)
- {
- spc=lll;
- pushdown(spc);
- }
- return spc;
- }
- void access(int spc)
- {
- int lst=,x;
- while(spc)
- {
- splay(spc);
- tr[lst].anc=;
- tr[rrr].anc=;
- x=leftpos(rrr);
- if(x&&!sta)
- update(,n,p[x].ind,p[x].oud,,);
- x=leftpos(lst);
- if(x&&!sta)
- update(,n,p[x].ind,p[x].oud,,-);
- rrr=lst;
- lst=spc;
- spc=tr[spc].fa;
- }
- return ;
- }
- void Mtr(int spc)
- {
- access(spc);
- splay(spc);
- trr(spc);
- return ;
- }
- void split(int x,int y)
- {
- Mtr(x);
- access(y);
- splay(y);
- return ;
- }
- void link(int x,int y)
- {
- split(x,y);
- tr[x].fa=y;
- return ;
- }
- int main()
- {
- scanf("%d%d",&n,&m);
- for(int i=;i<=n;i++)
- {
- tr[i].anc=true;
- }
- for(int i=;i<n;i++)
- {
- int a,b;
- scanf("%d%d",&a,&b);
- ade(a,b);
- ade(b,a);
- }
- dfs(,);
- build(,n,);
- sta=false;
- while(m--)
- {
- int cmd;
- scanf("%d",&cmd);
- if(cmd==)
- {
- int x;
- scanf("%d",&x);
- Mtr();
- access(x);
- }else if(cmd==)
- {
- int ans=;
- int x,y;
- scanf("%d%d",&x,&y);
- int z=Lca(x,y);
- ans+=query(,n,p[x].ind,);
- ans+=query(,n,p[y].ind,);
- ans-=query(,n,p[z].ind,)<<;
- printf("%d\n",ans);
- }else{
- int x;
- scanf("%d",&x);
- printf("%d\n",maxq(,n,p[x].ind,p[x].oud,));
- }
- }
- return ;
- }
BZOJ4817: [Sdoi2017]树点涂色(LCT)的更多相关文章
- [BZOJ4817][SDOI2017]树点涂色(LCT+DFS序线段树)
4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 692 Solved: 408[Submit][Status ...
- BZOJ4817[Sdoi2017]树点涂色——LCT+线段树
题目描述 Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色.Bob可能会进 ...
- 【BZOJ4817】[Sdoi2017]树点涂色 LCT+线段树
[BZOJ4817][Sdoi2017]树点涂色 Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路 ...
- [Bzoj4817] [Sdoi2017]树点涂色 (LCT神题)
4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 629 Solved: 371[Submit][Status ...
- [Sdoi2017]树点涂色 [lct 线段树]
[Sdoi2017]树点涂色 题意:一棵有根树,支持x到根染成新颜色,求x到y颜色数,求x子树里点到根颜色数最大值 考场发现这个信息是可减的,但是没想到lct 特意设计成lct的形式! 如何求颜色数? ...
- BZOJ 4817 [SDOI2017]树点涂色 (LCT+线段树维护dfs序)
题目大意:略 涂色方式明显符合$LCT$里$access$操作的性质,相同颜色的节点在一条深度递增的链上 用$LCT$维护一个树上集合就好 因为它维护了树上集合,所以它别的啥都干不了了 发现树是静态的 ...
- 【bzoj4817】树点涂色 LCT+线段树+dfs序
Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...
- BZOJ4817 [Sdoi2017]树点涂色 【LCT + 线段树】
题目 Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色.Bob可能会进行这 ...
- 【bzoj4817】[Sdoi2017]树点涂色 LCT+LCA+线段树
题目描述 给出一棵n个点,以1为根的有根树,每个点初始染有互不相同的颜色.定义一条路径的权值为路径上的颜色种类数.现有m次操作,每次操作为以下三种之一: 1 x: 把点x到根节点的路径上所有的点染上一 ...
随机推荐
- leetcode第一刷_Text Justification
这个题的接受率好低,搞得我一直不敢做.后来认真的看了一下题目,不是非常难嘛.字符串的题目ac率就是低,除了难,还由于它的測试用例太多. 思路不难,主要是由于特殊情况太多.纯模拟,我把全部的情况罗列一下 ...
- JsonRequestBehavior.AllowGet 方便浏览器调试
[HttpGet] public ActionResult getCoversationList(int CustomerId) { // 获取用户相关的聊天数据,包括个人,群,系统(可以单独获取) ...
- FZU--2188--过河(bfs暴力条件判断)
过河I Time Limit: 3000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u Submit Status De ...
- 23.IDEA 运行junit单元测试方法
转自:https://blog.csdn.net/weixin_42231507/article/details/80714716 配置Run,增加Junit 最终配置如下:
- 对Jscript操作注册表接口的一点不解
作者:朱金灿 来源:http://blog.csdn.net/clever101 要操作注册表需要通过ActiveX控件调用WScript.shell对象,通过该对象的一些方法来操作.Wshshell ...
- 定时器函数SetTimer
原文链接:http://www.cnblogs.com/zhangpengshou/archive/2009/04/05/1429770.html 一.SetTimer表示的是定义个定时器.根据定义指 ...
- 如何利用Python网络爬虫抓取微信好友数量以及微信好友的男女比例
前几天给大家分享了利用Python网络爬虫抓取微信朋友圈的动态(上)和利用Python网络爬虫爬取微信朋友圈动态——附代码(下),并且对抓取到的数据进行了Python词云和wordart可视化,感兴趣 ...
- nodejs操作文件和数据流
前言 node中有一组流api,它们可以像处理网络流一样处理文件.流api用起来非常方便,本节学习介绍文件处理基础和流的概念. 目录 处理文件路径 fs核心模块简介 操作流 慢客户端问题 1. 处理文 ...
- h5播放音乐
h5音频播放,里面參数能够查看http://www.w3school.com.cn/html5/html_5_audio.asp <audio controls="controls&q ...
- FocusChange-焦点变化监听事件
想要监听一个控件的焦点变化情况,发现了一个 view.setOnFocusChangeListener(new OnFocusChangeListener() { ...... } 现在写一个小dem ...