博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[SDOI2017]树点涂色
阅读量:5223 次
发布时间:2019-06-14

本文共 4642 字,大约阅读时间需要 15 分钟。

题目描述

Bob有一棵nn个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。

定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。

Bob可能会进行这几种操作:

  • 1 x

把点xx到根节点的路径上所有的点染上一种没有用过的新颜色。

  • 2 x y

xx到yy的路径的权值。

  • 3 x

在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。

Bob一共会进行mm次操作

输入输出格式

输入格式:

 

第一行两个数n,mn,m。

接下来n-1n1行,每行两个数a,ba,b,表示aa与bb之间有一条边。

接下来mm行,表示操作,格式见题目描述

 

输出格式:

 

每当出现2,3操作,输出一行。

如果是2操作,输出一个数表示路径的权值

如果是3操作,输出一个数表示权值的最大值

 

输入输出样例

输入样例#1:
5 61 22 33 43 52 4 53 31 42 4 51 52 4 5
输出样例#1:
3422

说明

共10个测试点

测试点1,1\leq n,m\leq10001n,m1000

测试点2、3,没有2操作

测试点4、5,没有3操作

测试点6,树的生成方式是,对于i(2\leq i \leq n)i(2in),在1到i-1i1中随机选一个点作为i的父节点。

测试点7,1\leq n,m\leq 500001n,m50000

测试点8,1\leq n \leq 500001n50000

测试点9,10,无特殊限制

对所有数据,1\leq n \leq 10^51n105​​,1\leq m \leq 10^51m105​​

时间限制:1s

空间限制:128MB

 

维护一个LCT,每个Splay里都是颜色相同的点.那么操作2的答案就是这两个点路径上的虚边的数量+1. 操作3的答案就是子树中每个点到根的路径虚边最大值+1.因为每次操作1都会用一种新的颜色,那么2的答案=f[x]+f[y]-2*f[lca(x,y)]+1.f[x]代表x到根的路径上的虚边数量.
然后这个东西显然树链剖分用线段树来维护,顺便求出lca.那么操作2为单点查询,操作3为区间查询(dfn).
然后再考虑操作1对查询的影响.
用LCT中的access操作,每次将一条实边变成虚边的时候,将这颗子树中的值全部加1,虚边变实边相反. 这里有一个细节没有考虑到,因为这条路径是用Splay存的,那么原树上与这条要修改的边相连的点并不是Splay中与这条边相连的那个点. 所以区间修改时要找最浅的那个点,即为Splay中那颗子树的最左边的点.
1 #include
2 #define ls o*2 3 #define rs o*2+1 4 #define pre t[x].fa 5 #define LS t[x].ch[0] 6 #define RS t[x].ch[1] 7 #define maxn 100010 8 #define RG register 9 using namespace std; 10 struct Edge{ 11 int nex,to; 12 }e[maxn*2]; 13 struct lct{
int w,ch[2],fa;}t[maxn]; 14 int head[maxn],edge=0,top[maxn],dfn[maxn],dfp[maxn],dad[maxn],ed[maxn],deep[maxn],son[maxn],size[maxn]; 15 int n,b[maxn*4],lazy[maxn*4]; 16 inline void add(int from,int to){ 17 e[++edge].nex=head[from]; 18 e[edge].to=to; 19 head[from]=edge; 20 } 21 void dfs1(int x,int fa){ 22 size[x]=1; 23 for(RG int i=head[x];i;i=e[i].nex){ 24 int v=e[i].to; 25 if(v==fa) continue; 26 deep[v]=deep[x]+1; 27 dad[v]=x;t[v].fa=x; 28 dfs1(v,x); 29 size[x]+=size[v]; 30 if(size[v]>size[son[x]])son[x]=v; 31 } 32 } 33 int de=0; 34 void dfs2(int x,int fa){ 35 dfn[x]=++de;dfp[de]=x; 36 if(son[x])top[son[x]]=top[x],dfs2(son[x],x); 37 for(int i=head[x];i;i=e[i].nex){ 38 int v=e[i].to; 39 if(v==fa || v==son[x])continue; 40 top[v]=v; 41 dfs2(v,x); 42 } 43 ed[x]=de; 44 } 45 void build(int o,int l,int r){ 46 if(l==r){b[o]=deep[dfp[l]];return;} 47 int mid=(l+r)>>1; 48 build(ls,l,mid);build(rs,mid+1,r); 49 b[o]=max(b[ls],b[rs]); 50 } 51 inline void down(int o){ 52 if(lazy[o]){ 53 int k=lazy[o];lazy[o]=0; 54 b[ls]+=k,b[rs]+=k,lazy[ls]+=k,lazy[rs]+=k; 55 } 56 } 57 void change(int o,int l,int r,int u,int v,int w){ 58 if(l!=r) down(o); 59 if(l>v || r
=u && r<=v){b[o]+=w,lazy[o]+=w;return;} 61 int mid=(l+r)>>1; 62 if(v<=mid) change(ls,l,mid,u,v,w); 63 else if(u>mid) change(rs,mid+1,r,u,v,w); 64 else change(ls,l,mid,u,mid,w),change(rs,mid+1,r,mid+1,v,w); 65 b[o]=max(b[ls],b[rs]); 66 } 67 inline bool isrt(int x){
return t[pre].ch[0]!=x && t[pre].ch[1]!=x;} 68 inline bool Son(int x){
return t[pre].ch[1]==x;} 69 inline void Rotate(int x){ 70 int f=t[x].fa,g=t[f].fa,c=Son(x); 71 if(!isrt(f)) t[g].ch[Son(f)]=x; 72 t[x].fa=g; 73 t[f].ch[c]=t[x].ch[c^1],t[t[f].ch[c]].fa=f; 74 t[x].ch[c^1]=f,t[f].fa=x; 75 } 76 inline void Splay(int x){ 77 for(;!isrt(x);Rotate(x)) 78 if(!isrt(pre)) Rotate(Son(pre)==Son(x)?pre:x); 79 } 80 inline void access(int x){ 81 for(RG int y=0;x;y=x,x=pre){ 82 Splay(x);if(RS){ 83 int kp=RS; 84 while(t[kp].ch[0])kp=t[kp].ch[0]; 85 change(1,1,n,dfn[kp],ed[kp],1); 86 } 87 RS=y;if(RS){ 88 int kp=RS; 89 while(t[kp].ch[0])kp=t[kp].ch[0]; 90 change(1,1,n,dfn[kp],ed[kp],-1); 91 } 92 } 93 } 94 int Find(int o,int l,int r,int p){ 95 if(l!=r) down(o); 96 if(l==r) return b[o]; 97 int mid=(l+r)>>1; 98 if(p<=mid)return Find(ls,l,mid,p); 99 else return Find(rs,mid+1,r,p);100 }101 int query(int o,int l,int r,int u,int v){102 if(l!=r) down(o);103 if(l>v || r
=u && r<=v) return b[o];105 int mid=(l+r)>>1;106 if(v<=mid) return query(ls,l,mid,u,v);107 else if(u>mid) return query(rs,mid+1,r,u,v);108 else return max(query(ls,l,mid,u,mid),query(rs,mid+1,r,mid+1,v));109 }110 inline void lca(int x,int y){111 int xx=x,yy=y,LCA;112 while(top[x]!=top[y]){113 if(deep[top[x]]>deep[top[y]])x=dad[top[x]];114 else y=dad[top[y]];115 }116 LCA=deep[x]>deep[y]?y:x;117 printf("%d\n",Find(1,1,n,dfn[xx])+Find(1,1,n,dfn[yy])-2*Find(1,1,n,dfn[LCA])+1);118 }119 int main(){120 int m,type,x,y;121 scanf("%d%d",&n,&m);122 for(RG int i=1;i
 

 

 

转载于:https://www.cnblogs.com/pantakill/p/7282480.html

你可能感兴趣的文章
win7创建共享给windows和linux机器
查看>>
java RE Validation常用
查看>>
How to change MAC address in windows 7
查看>>
log4net的各种Appender配置示例
查看>>
JointCode.Shuttle,一个简单高效的跨 AppDomain 通信的服务框架
查看>>
迅为iTOP-4412开发板-驱动-显卡支持HDMI_1080P分辨率
查看>>
SQL点点滴滴_DELETE小计
查看>>
Jquery选择器
查看>>
苹果开发者账号那些事儿(二)
查看>>
鲜贝7.3--mysql 下载小问题
查看>>
重载构造函数
查看>>
SimpleAdapter
查看>>
python中os的常用方法
查看>>
你的MongoDB Redis设置用户名密码了吗?看看shodan这款邪恶的搜索引擎吧!~
查看>>
selenium第二课(脚本录制seleniumIDE的使用)
查看>>
带权并查集
查看>>
DB2基础(增删改查)
查看>>
python 常用的50个模块
查看>>
音视频合成相关
查看>>
懒,不是理由
查看>>