【Foreign】染色 [LCT][线段树]

染色

Time Limit: 20 Sec  Memory Limit: 256 MB

Description

  

Input

  

Output

  

Sample Input

  13
  0 1
  0 2
  1 11
  1 10
  1 9
  9 12
  2 5
  5 8
  2 4
  2 3
  4 6
  4 7
  7
  q 0
  O 4
  q 6
  q 2
  O 9
  q 9
  q 2

Sample Output

  2.0000000000
  1.0000000000
  0.8571428571
  0.5000000000
  1.8571428571

HINT

  

Main idea

  询问x到根路径上不同颜色的个数,支持将x到根的路径上的点全部设为新的颜色。

Source

  我们将边两端的点颜色相同的边设为实边不同的设为虚边。那么一次新增颜色的操作显然就是LCT的access操作!access的时候恰是虚边和实边的转换。

  那么我们只要用线段树维护每个点到根的贡献,结合dfs序来实现子树加,每次在LCT进行access的时候进行+-1修改,然后询问的时候用区间求和求得答案即可。

Code

  1 #include<iostream>
  2 #include<string>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<ctime>
  8 #include<cmath>
  9 using namespace std;
 10 typedef long long s64;
 11 const int ONE=1500001;
 12
 13 int n,m,x,y;
 14 int pos[ONE],size[ONE],Dep[ONE],dfn[ONE],cnt;
 15 s64 res;
 16 char ch[5];
 17
 18 int lc[ONE],rc[ONE],fa[ONE];
 19
 20 int get()
 21 {
 22         int res=1,Q=1;char c;
 23         while( (c=getchar())<48 || c>57 )
 24         if(c==‘-‘)Q=-1;
 25         res=c-48;
 26         while( (c=getchar())>=48 && c<=57 )
 27         res=res*10+c-48;
 28         return res*Q;
 29 }
 30
 31 namespace tree
 32 {
 33         int next[ONE],first[ONE],go[ONE],tot;
 34
 35         void Add(int u,int v)
 36         {
 37             next[++tot]=first[u];    first[u]=tot;    go[tot]=v;
 38             next[++tot]=first[v];    first[v]=tot;    go[tot]=u;
 39         }
 40
 41         void Dfs(int u,int father)
 42         {
 43             pos[u] = ++cnt; dfn[cnt] = u;
 44             size[u] = 1;
 45             for(int e=first[u];e;e=next[e])
 46             {
 47                 int v=go[e];
 48                 if(v==father) continue;
 49                 Dep[v] = Dep[u] + 1;
 50                 fa[v] = u;
 51                 Dfs(v,u);
 52                 size[u] += size[v];
 53             }
 54         }
 55 }
 56
 57 namespace Seg
 58 {
 59         struct power
 60         {
 61             s64 add,value;
 62         }Node[ONE];
 63
 64         void pushdown(int i,int Q)
 65         {
 66             if(Node[i].add)
 67             {
 68                 Node[i<<1].add+=Node[i].add;
 69                 Node[i<<1|1].add+=Node[i].add;
 70                 Node[i<<1].value+=Node[i].add*(Q-Q/2);
 71                 Node[i<<1|1].value+=Node[i].add*(Q/2);
 72                 Node[i].add=0;
 73             }
 74         }
 75
 76         void Build(int i,int l,int r)
 77         {
 78             if(l==r)
 79             {
 80                 Node[i].value = Dep[dfn[l]];
 81                 return;
 82             }
 83             int mid=(l+r)>>1;
 84             Build(i<<1,l,mid);    Build(i<<1|1,mid+1,r);
 85             Node[i].value=Node[i<<1].value+Node[i<<1|1].value;
 86         }
 87
 88         void Update(int i,int l,int r,int L,int R,int x)
 89         {
 90             if(L<=l && r<=R)
 91             {
 92                 Node[i].add+=x;
 93                 Node[i].value+=(s64)(r-l+1)*x;
 94                 return;
 95             }
 96
 97             pushdown(i,r-l+1);
 98             int mid=(l+r)>>1;
 99             if(L<=mid) Update(i<<1,l,mid,L,R,x);
100             if(mid+1<=R) Update(i<<1|1,mid+1,r,L,R,x);
101             Node[i].value=Node[i<<1].value+Node[i<<1|1].value;
102         }
103
104         void Query(int i,int l,int r,int L,int R)
105         {
106             if(L<=l && r<=R)
107             {
108                 res+=Node[i].value;
109                 return;
110             }
111             pushdown(i,r-l+1);
112             int mid=(l+r)>>1;
113             if(L<=mid) Query(i<<1,l,mid,L,R);
114             if(mid+1<=R) Query(i<<1|1,mid+1,r,L,R);
115         }
116 }
117
118 namespace LCT
119 {
120         int is_real(int x)
121         {
122             return (lc[fa[x]]==x || rc[fa[x]]==x);
123         }
124
125         void Turn(int x)
126         {
127             int y=fa[x],z=fa[y];
128             int b= x==lc[y] ? rc[x]:lc[x];
129
130             fa[x]=z;    fa[y]=x;
131             if(b) fa[b]=y;
132
133             if(z)
134             {
135                 if(y==lc[z]) lc[z]=x;
136                 else
137                 if(y==rc[z]) rc[z]=x;
138             }
139
140             if(x==lc[y]) rc[x]=y,lc[y]=b;
141             else lc[x]=y,rc[y]=b;
142         }
143
144         void Splay(int x)
145         {
146             while(is_real(x))
147             {
148                 if(is_real(fa[x]))
149                 {
150                     if( (lc[fa[x]]==x) == (lc[fa[fa[x]]]==fa[x]) ) Turn(fa[x]);
151                     else Turn(x);
152                 }
153                 Turn(x);
154             }
155         }
156
157         int find_root(int x)
158         {
159             while(lc[x]) x=lc[x];
160             return x;
161         }
162
163         void access(int x)
164         {
165             for(int p=x,q=0; p; q=p,p=fa[p])
166             {
167                 Splay(p);
168                 if(rc[p])
169                 {
170                     int N=find_root(rc[p]);
171                     Seg::Update(1,1,n,pos[N],pos[N]+size[N]-1,+1);
172                 }
173                 rc[p]=q;
174                 if(rc[p])
175                 {
176                     int N=find_root(rc[p]);
177                     Seg::Update(1,1,n,pos[N],pos[N]+size[N]-1,-1);
178                 }
179             }
180         }
181 }
182
183 int main()
184 {
185         n=get();
186         for(int i=1;i<n;i++)
187         {
188             x=get();    y=get();
189             x++;    y++;
190             tree::Add(x,y);
191         }
192         tree::Dfs(1,0);
193         Seg::Build(1,1,n);
194
195         m=get();
196         while(m--)
197         {
198             scanf("%s",ch);    x=get(); x++;
199             if(ch[0]==‘O‘)
200             {
201                 LCT::access(x);
202             }
203             else
204             {
205                 res=0;
206                 Seg::Query(1,1,n,pos[x],pos[x]+size[x]-1);
207                 printf("%.10lf\n",(double)res/size[x]);
208             }
209         }
210
211 }

时间: 2024-10-11 07:27:52

【Foreign】染色 [LCT][线段树]的相关文章

BZOJ 3779 重组病毒 LCT+线段树维护DFS序

题目大意:给定一棵树,初始每个点都有一个颜色,支持三种操作: 1.将某个点到根的路径上所有点染上一种新的颜色 2.将某个点到根的路径上所有点染上一种新的颜色,然后把根设为这个点 3.定义一个点的代价为这个点到根路径上颜色的种类数,求某个点子树中所有点代价的平均值 我真是炖了狗了-- 容易发现这玩应就是个LCT,操作1就是Access,操作2就是Move_To_Root,代价就是一个点到根路径上的虚边数量+1 我们用LCT模拟上述操作,用线段树维护DFS序维护信息,一旦LCT中出现了虚实边的切换,

【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]

树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色.Bob可能会进行这几种操作: 1 x: 把点x到根节点的路径上所有的点染上一种没有用过的新颜色. 2 x y: 求x到y的路径的权值. 3 x: 在以x为根的子

BZOJ 3779 重组病毒 LCT+线段树(维护DFS序)

原题干(由于是权限题我就直接砸出原题干了,要看题意概述的话在下面): Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒.实验在一个封闭的局域网内进行.局域网内有n台计算机,编号为1~n.一些计算机之间通过网线直接相连,形成树形的结构.局域网中有一台特殊的计算机,称之为核心计算机.根据一些初步的研究,研究员们拟定了一个一共m步的实验.实验开始之前,核

BZOJ 4530 LCT/线段树合并

//By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=200050; int n,q,cnt,dfn[N],last[N],tree[N*16],lson[N*16],rson[N*16]; int first[N],next[N],v[N],w[N],tot,root[N],fa[N],deep[N],f[N];

BZOJ 3779 LCT 线段树 DFS序 坑

hhhh抄了半天lty代码最后T了  对拍也没事.. 药丸 mine #pragma GCC optimize("O3") //By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=100500; typedef long long ll; int n,m,xx,yy,first[N],next[N*2],v[N*2],tot; int in[N],out[N],deep[N],p[N]

ACM: Copying Data 线段树-成段更新-解题报告

Copying Data Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Description We often have to copy large volumes of information. Such operation can take up many computer resources. Therefore, in this problem you are advised to come

hdu_5818_Joint Stacks(线段树模拟)

题目链接:hdu_5818_Joint Stacks 题意: 给你两个栈,多了个合并操作,然后让你模拟 题解: 很容易想到O(1)的单个栈操作,O(n)的合并操作,这样肯定超时,所以我们要将时间复杂度均摊一下,让每个操作都是logn的,于是用上了线段树模拟. 线段树考虑染色,线段树的区间代表的是操作编号,0代表为A栈,1代表为B栈,每次merge 就把1到i这个区间染成指定颜色,然后pop就在线段树中找最右边的对应颜色的点.这样每次操作都是logn 不过官方题解给的是O(n)的解法,反正我是没想

BZOJ.4817.[SDOI2017]树点涂色(LCT DFS序 线段树)

题目链接 1.2裸树剖,但是3.每个点的答案val很不好维护.. 如果我们把同种颜色的点划分到同一连通块中,那么向根染色的过程就是Access()! 最初所有点间都是虚边,相同颜色点用实边相连.一条边由实边变为虚边时,深度大的点所在子树所有点val+1(Access()中原先x的右儿子答案+1,因为x颜色变了): 由虚边变为实边时,深度大的点所在子树所有点val-1(fa[x]颜色与x相同导致fa[x]的贡献没了).(其实是因为 实链数量(贡献)就等于虚边数量+1?无所谓了) 于是2.就是val

线段树分治总结(线段树分治,线段树,并查集,树的dfn序,二分图染色)

闲话 stO猫锟学长,满脑子神仙DS 线段树分治思想 我们在做CDQ的时候,将询问和操作通通视为元素,在归并过程中统计左边的操作对右边的询问的贡献. 而在线段树分治中,询问被固定了.按时间轴确定好询问的序列以后,我们还需要所有的操作都会影响一个时间区间.而这个区间,毫无疑问正好对应着询问的一段区间. 于是,我们可以将每一个操作丢到若干询问里做区间修改了,而线段树可以高效地维护.我们开一个叶子节点下标为询问排列的线段树,作为分治过程的底层结构. 具体的实现,仍然要看题目. 例题1 BZOJ4025