3779: 重组病毒

传送门

一道很有奥妙的题.

发现修改操作和access有着不可不说的关系.

因为操作的特殊性,每种颜色在树上是一段连续的区间.不会被切开.

若x跟父亲颜色相同,设x到父亲的边的权值为0,否则为1

那么一个点到根的颜色就是它到跟路径上1的个数+1

修改从x到根,x到根的边全都变成0,x到跟路径上相邻的其他边都变成1

把1看成虚边,0看出实边,就相当于access操作

用lct维护即可得到每次需要修改的边,修改一条边相当于子树修改,线段树维护dfs序即可

newroot时候不需要单独处理,只需access的时候加减.注意access的时候加减的是rc/t那颗splay中深度最浅的节点,不是rc/t本身

查询修改都同遥远的国度,分类讨论.(注意修改也要讨论呀...你是改子树呀...)

然后观察了一下别人的代码,发现找我包含根的那个儿子不应该暴力枚举我的儿子而应该预处理倍增数组从根跳,,改了一下..虽然数据也不卡我...

  1 //Achen
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdlib>
  6 #include<vector>
  7 #include<cstdio>
  8 #include<queue>
  9 #include<cmath>
 10 #include<set>
 11 #include<map>
 12 #define For(i,a,b) for(int i=(a);i<=(b);i++)
 13 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
 14 const int N=3e5+7;
 15 typedef long long LL;
 16 typedef double db;
 17 using namespace std;
 18 int n,m,rt;
 19 char o[15];
 20
 21 template<typename T> void read(T &x) {
 22     char ch=getchar(); x=0; T f=1;
 23     while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘)) ch=getchar();
 24     if(ch==‘-‘) f=-1,ch=getchar();
 25     for(;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=x*10+ch-‘0‘; x*=f;
 26 }
 27
 28 int ecnt,fir[N],nxt[N<<1],to[N<<1];
 29 void add(int u,int v) {
 30     nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
 31     nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
 32 }
 33
 34 LL sg[N<<2],lz[N<<2];
 35 #define ls x<<1
 36 #define rs ((x<<1)|1)
 37 #define mid ((l+r)>>1)
 38 void down(int x,int l_len,int r_len) {
 39     if(!lz[x]) return;
 40     if(l_len) sg[ls]=sg[ls]+l_len*lz[x],lz[ls]=lz[ls]+lz[x];
 41     if(r_len) sg[rs]=sg[rs]+r_len*lz[x],lz[rs]=lz[rs]+lz[x];
 42     lz[x]=0;
 43 }
 44
 45 void update(int x,int l,int r,int ql,int qr,int v) {
 46     if(ql>qr) return;
 47     if(l>=ql&&r<=qr) {
 48         sg[x]=sg[x]+(LL)(r-l+1)*v;
 49         lz[x]=lz[x]+v; return;
 50     }
 51     down(x,mid-l+1,r-mid);
 52     if(ql<=mid) update(ls,l,mid,ql,qr,v);
 53     if(qr>mid) update(rs,mid+1,r,ql,qr,v);
 54     sg[x]=sg[ls]+sg[rs];
 55 }
 56
 57 LL qry(int x,int l,int r,int ql,int qr) {
 58     if(ql>qr) return 0;
 59     if(l>=ql&&r<=qr) return sg[x];
 60     down(x,mid-l+1,r-mid);
 61     if(qr<=mid) return qry(ls,l,mid,ql,qr);
 62     if(ql>mid) return qry(rs,mid+1,r,ql,qr);
 63     return qry(ls,l,mid,ql,qr)+qry(rs,mid+1,r,ql,qr);
 64 }
 65
 66 int p[N],ch[N][2],flip[N],st[N][20];
 67
 68 int sz[N],fa[N],dfn[N],R[N],dfs_clock;
 69 void dfs(int x,int FA) {
 70     sz[x]=1;
 71     p[x]=FA;
 72     fa[x]=FA;
 73     st[x][0]=FA;
 74     For(i,1,19) st[x][i]=st[st[x][i-1]][i-1];
 75     R[x]=R[FA]+1;
 76     dfn[x]=++dfs_clock;
 77     update(1,1,n,dfn[x],dfn[x],R[x]);
 78     for(int i=fir[x];i;i=nxt[i]) if(to[i]!=FA) {
 79         dfs(to[i],x);
 80         sz[x]+=sz[to[i]];
 81     }
 82 }
 83
 84 #define lc ch[x][0]
 85 #define rc ch[x][1]
 86
 87 void down(int x) {
 88     if(!flip[x]) return;
 89     swap(lc,rc);
 90     flip[lc]^=1;
 91     flip[rc]^=1;
 92     flip[x]^=1;
 93 }
 94
 95 int isroot(int x) { return ch[p[x]][0]!=x&&ch[p[x]][1]!=x; }
 96
 97 void rotate(int x) {
 98     int y=p[x],z=p[y],l=(x==ch[y][1]),r=l^1;
 99     if(!isroot(y)) ch[z][y==ch[z][1]]=x; p[x]=z;
100     ch[y][l]=ch[x][r]; p[ch[x][r]]=y;
101     ch[x][r]=y; p[y]=x;
102 }
103
104 void splay(int x) {
105     static int g[N],top=0,tp;
106     for(tp=x;!isroot(tp);tp=p[tp]) g[++top]=tp;
107     g[++top]=tp;
108     while(top) down(g[top--]);
109     for(;!isroot(x);rotate(x)) {
110         int y=p[x],z=p[y];
111         if(!isroot(y)) ((x==ch[y][1])^(y==ch[z][1]))?rotate(x):rotate(y);
112     }
113 }
114
115 void change(int x,int v) {
116     if(x==rt) update(1,1,n,1,n,v);
117     else if(dfn[rt]>dfn[x]&&dfn[rt]<dfn[x]+sz[x]) {
118         int y=rt;
119         Rep(i,19,0) if(R[st[y][i]]>R[x]) y=st[y][i];
120            /*for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa[x]) {
121             y=to[i];
122             if(dfn[rt]>=dfn[y]&&dfn[rt]<dfn[y]+sz[y]) break;
123         } */
124         update(1,1,n,1,dfn[y]-1,v);
125         update(1,1,n,dfn[y]+sz[y],n,v);
126        }
127        else update(1,1,n,dfn[x],dfn[x]+sz[x]-1,v);
128 }
129
130 void access(int x) {
131     for(int t=0;x;x=p[t=x]) {
132         splay(x);
133         if(rc) {
134             int tp=rc; down(tp); while(ch[tp][0]) { tp=ch[tp][0]; down(tp); }
135             change(tp,1); //shi bian xu
136         }
137         if(t) {
138             int tp=t; down(tp); while(ch[tp][0]) { tp=ch[tp][0]; down(tp); }
139             change(tp,-1); // xu bian shi
140         }
141         rc=t;
142     }
143 }
144
145 void newroot(int x) {
146     access(x);
147     splay(x);
148     flip[x]^=1;
149     rt=x;
150 }
151
152 void solve(int x) {
153     db ans=0.0;
154     if(x==rt) ans=(db)sg[1]/(1.0*n);
155     else if(dfn[rt]>dfn[x]&&dfn[rt]<dfn[x]+sz[x]) {
156         /*int y=0;
157            for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa[x]) {
158             y=to[i];
159             if(dfn[rt]>=dfn[y]&&dfn[rt]<dfn[y]+sz[y]) break;
160         }*/
161         int y=rt;
162         Rep(i,19,0) if(R[st[y][i]]>R[x]) y=st[y][i];
163         ans=((db)qry(1,1,n,1,dfn[y]-1)+qry(1,1,n,dfn[y]+sz[y],n))/(1.0*(n-sz[y]));
164        }
165        else ans=(db)qry(1,1,n,dfn[x],dfn[x]+sz[x]-1)/(1.0*sz[x]);
166     printf("%.10lf\n",ans);
167 }
168
169 //#define DEBUG
170 int main() {
171 #ifdef DEBUG
172     freopen("3779.in","r",stdin);
173     freopen("3779.out","w",stdout);
174 #endif
175     read(n); read(m); rt=1;
176     For(i,2,n) {
177         int x,y;
178         read(x); read(y);
179         add(x,y);
180     }
181     dfs(rt,0);
182     For(ti,1,m) {
183         int x;
184         scanf("%s",o); read(x);
185         if(o[2]==‘L‘) access(x);
186         else if(o[2]==‘C‘) newroot(x);
187         else if(o[2]==‘Q‘) solve(x);
188     }
189     return 0;
190 }

原文地址:https://www.cnblogs.com/Achenchen/p/8982689.html

时间: 2024-11-02 23:38:15

3779: 重组病毒的相关文章

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

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

bzoj 3779 重组病毒 —— LCT+树状数组(区间修改+区间查询)

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779 RELEASE操作可以对应LCT的 access,RECENTER则是 makeroot: 考虑颜色数,把一条实边变成虚边,子树+1,虚变实子树-1: 但有换根操作,怎么维护子树? 也可以用 dfs 序线段树维护,其实换 rt 只是 splay 的根方向改变,对应的子树还是可以找到的: 注意虚边变实或实边变虚时要找子树,不是直接找那个儿子,而是找那个儿子所在 splay 的根: 然后

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

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

【BZOJ-3779】重组病毒 LinkCutTree + 线段树 + DFS序

3779: 重组病毒 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 224  Solved: 95[Submit][Status][Discuss] Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒.实验在一个封闭的局域网内进行.局域网内有n台计算机,编号为1~n.一些计算机之间通过网线直接相连,形

【bzoj 3779】重组病毒

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

【BZOJ3779】重组病毒 LCT+DFS序

[BZOJ3779]重组病毒 Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒.实验在一个封闭的局域网内进行.局域网内有n台计算机,编号为1~n.一些计算机之间通过网线直接相连,形成树形的结构.局域网中有一台特殊的计算机,称之为核心计算机.根据一些初步的研究,研究员们拟定了一个一共m步的实验.实验开始之前,核心计算机的编号为1,每台计算机中都有病毒

【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询

题目描述 给出一棵n个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1. 定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目. 现有m次操作,每次为一下三种之一: RELEASE x:对x执行一次感染: RECENTER x:把根节点改为x,并对原来的根节点执行一次感染: REQUEST x:询问x子树中所有节点感染代价的平均值. 输入 输入的第一行包含两个整数n和m,分别代表局域网中计算机的数量,以及操作和询问的总数.接下来n-1行,

【算法总结】树相关

[点分治] [模板代码] 1 void getroot(int x,int fa) 2 { 3 sz[x]=1;mx[x]=0; 4 for(int i=first[x];i;i=e[i].next) 5 { 6 int to=e[i].to; 7 if(to==fa||vis[to])continue; 8 getroot(to,x); 9 sz[x]+=sz[to]; 10 mx[x]=max(mx[x],sz[to]); 11 } 12 mx[x]=max(mx[x],sum-sz[x])

多校联考九场总结

总算考完了九套试题,天天早上坐五个小时,下午都会头痛的要死QAQ 不过考的貌似不错? 九场平均分 215.78 数一数考场上没有1A的题目吧(不算有毒的OJ卡我常数): 1.超立方体 QAQ 当时并不会FWT,矩阵乘法搞出系数来之后只能暴力贡献 然后输入的时候没有直接取模爆了long long,于是暴力也被炸飞了 后来学了FWT发现是水题 2.IP地址 没有使用合适的转化询问的方式 使得这道题目可以用打标记的方式来做 转化的一些经典方式:差分,叶节点查询转化为链求和,区间可减性查询转化为前缀查询