bzoj 3779 重组病毒——LCT维护子树信息
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779
调了很久……已经懒得写题解了。https://www.cnblogs.com/Zinn/p/10124183.html
线段树和LCT是分开的。线段树的子树一直是相对于 1 号点而言。线段树上维护的值总是相对于当前的 rt 的。
怎么保证一直是相对于当前 rt 的呢?发现如果 rt 和 rt' 之间的链上全是重边,则每个子树对于 rt 的答案和对于 rt' 的答案是一样的。
所以在换 rt 的时候先按相对于原 rt 的情况把子树信息维护好,等到把链都弄成重边之后,值们自然而然就变成相对于新 rt 的了。
写了区间修改区间查询的树状数组。
注意树状数组的 add( ) 里传的那个 k 应该是 long long 类型!!!因为有 init( ) ,所以它传的不是 +1 * (int以内的数) ,还是可能爆 int 的!!!
但为什么总是对拍不出问题?大概因为自己建的是随机树,深度期望 log ;i * d[ i ] 的那个 d[ i ] (差分数组)是对深度的差分,所以总是拍不出错吧。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define ls Ls[cr]
#define rs Rs[cr]
using namespace std;
const int N=1e5+,K=;
int n,hd[N],xnt,to[N<<],nxt[N<<],rt;
int dep[N],fa[N],pre[N][K],c[N][],dfn[N],siz[N],tot;
int sta[N],top; ll tmp[N],f[N],fi[N]; bool rev[N];
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void dfs(int cr)
{
dfn[cr]=++tot;siz[cr]=;
dep[cr]=dep[fa[cr]]+;tmp[tot]=dep[cr];
pre[cr][]=fa[cr];
for(int i=;pre[pre[cr][i-]][i-];i++)
pre[cr][i]=pre[pre[cr][i-]][i-];
for(int i=hd[cr],v;i;i=nxt[i])
if(!dfn[v=to[i]])
{
fa[v]=cr;dfs(v);
siz[cr]+=siz[v];
}
}
void add(int x,ll k,ll *f){for(;x<=n;x+=(x&-x))f[x]+=k;}//ll k! for init
ll qry(int x,ll *f){ll ret=;for(;x;x-=(x&-x))ret+=f[x];return ret;}
ll qry(int x)
{
ll ret=;int yx=x+;
for(;x;x-=(x&-x))ret+=(ll)yx*f[x]-fi[x];return ret;
}
void init()
{
for(int i=n;i;i--)tmp[i]-=tmp[i-],add(i,tmp[i],f);
for(int i=;i<=n;i++)tmp[i]*=i,add(i,tmp[i],fi);
}
void mdfy(int L,int R,int k)
{
if(L>R)return;/////
add(L,k,f);add(R+,-k,f);
add(L,k*L,fi);add(R+,-k*(R+),fi);
}
ll query(int L,int R)
{
if(L>R)return ;///
ll a=(R+)*qry(R,f)-qry(R,fi);
ll b=L*qry(L-,f)-qry(L-,fi);
return a-b;
}
bool isroot(int x){return c[fa[x]][]!=x&&c[fa[x]][]!=x;}
void Rev(int x)
{
if(!rev[x])return;rev[x]=;
rev[c[x][]]^=;rev[c[x][]]^=;
swap(c[x][],c[x][]);
}
void rotate(int x)
{
int y=fa[x],z=fa[y],d=(x==c[y][]);
if(!isroot(y))c[z][y==c[z][]]=x;
fa[x]=z;
fa[c[x][!d]]=y;fa[y]=x;
c[y][d]=c[x][!d];c[x][!d]=y;
}
void splay(int x)
{
sta[top=]=x;
for(int k=x;!isroot(k);k=fa[k])sta[++top]=fa[k];
for(int i=top;i;i--)Rev(sta[i]);
int y,z;
while(!isroot(x))
{
y=fa[x];z=fa[y];
if(!isroot(y))
((x==c[y][])^(y==c[z][]))?rotate(x):rotate(y);
rotate(x);
}
}
int fnd(int x)
{Rev(x);while(c[x][])x=c[x][],Rev(x);return x;}
int fnd(int x,int f)
{
for(int i=;i>=;i--)
if(dep[pre[x][i]]>dep[f])x=pre[x][i];
return x;
}
bool intree(int x,int rt)
{return dfn[x]>=dfn[rt]&&dfn[x]<dfn[rt]+siz[rt];}
void chg(int x,int k)
{
if(!intree(rt,x))mdfy(dfn[x],dfn[x]+siz[x]-,k);
else
{
int d=fnd(rt,x);//d!!
mdfy(,dfn[d]-,k);mdfy(dfn[d]+siz[d],n,k);
}
}
void access(int x)
{
int t=;
while(x)
{
splay(x);
if(c[x][])chg(fnd(c[x][]),);
if(t)chg(fnd(t),-);
c[x][]=t;
t=x;x=fa[x];
}
}
void makeroot(int x)
{
access(x);splay(x);rev[x]^=;rt=x;//rt=x after access(x)
}
double query(int x)
{
if(x==rt) return (double)query(,n)/n;
if(intree(rt,x))
{
int d=fnd(rt,x);
ll ret=query(,dfn[d]-)+query(dfn[d]+siz[d],n);
return (double)ret/(n-siz[d]);
}
return (double)query(dfn[x],dfn[x]+siz[x]-)/siz[x];
}
int main()
{
n=rdn();int Q=rdn();
for(int i=,u,v;i<n;i++)
{
u=rdn();v=rdn();add(u,v);add(v,u);
}
dfs();init();
char ch[];int x;rt=;
while(Q--)
{
scanf("%s",ch);x=rdn();
if(ch[]=='L')access(x);
if(ch[]=='C')makeroot(x);
if(ch[]=='Q')printf("%.10f\n",query(x));
}
return ;
}
bzoj 3779 重组病毒——LCT维护子树信息的更多相关文章
- BZOJ 3779 重组病毒 LCT+线段树(维护DFS序)
原题干(由于是权限题我就直接砸出原题干了,要看题意概述的话在下面): Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力 ...
- bzoj 4530 大融合 —— LCT维护子树信息
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4530 用LCT维护子树 size,就是实边和虚边分开维护: 看博客:https://blog ...
- bzoj 3779: 重组病毒 LCT+线段树+倍增
题目: 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒. 实验在一个封闭 ...
- bzoj 3779 重组病毒 —— LCT+树状数组(区间修改+区间查询)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779 RELEASE操作可以对应LCT的 access,RECENTER则是 makeroo ...
- BZOJ 3779 重组病毒 ——LCT 线段树
发现操作一很像一个LCT的access的操作. 然后答案就是路径上的虚边的数量. 然后考虑维护每一个点到根节点虚边的数量, 每次断开一条偏爱路径的时候,子树的值全部+1, 连接一条偏爱路径的时候,子树 ...
- 【bzoj4530】[Bjoi2014]大融合 LCT维护子树信息
题目描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量 ...
- 【uoj#207】共价大爷游长沙 随机化+LCT维护子树信息
题目描述 给出一棵树和一个点对集合S,多次改变这棵树的形态.在集合中加入或删除点对,或询问集合内的每组点对之间的路径是否都经过某条给定边. 输入 输入的第一行包含一个整数 id,表示测试数据编号,如第 ...
- 【bzoj3510】首都 LCT维护子树信息(+启发式合并)
题目描述 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失, ...
- 【BZOJ3510】首都 LCT维护子树信息+启发式合并
[BZOJ3510]首都 Description 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打 ...
随机推荐
- Valgrind查找内存泄露利器
Valgrind是一个GPL的软件,用于Linux(For x86, amd64 and ppc32)程序的内存调试和代码剖析.你可以在它的环境中运行你的程序来监视内存的使用情况,比如C 语言中的ma ...
- C++复习8.异常处理和RTTI
C++异常处理和RTTI技术 20130930 1.异常处理的基本知识 C语言中是没有内置运行时错误处理机制,对于错误发生的时候使用的几种处理机制: 函数返回彼此协商后统一定义的状态编码来表示操作成功 ...
- 【zzuli-2266】number(二进制处理)
题目描述 某人刚学习了数位DP,他在某天忽然思考如下问题: 给定n,问有多少数对<x, y>满足: x, y∈[1, n], x < y x, y中出现的[0, 9]的数码种类相同 ...
- C# 中移动文件到指定位置
根据文件后缀名称将文件移动到指定的文件夹下面,具体代码如下: demo中使用的是 .png 具体的情况根据你的需求可以更改 using System; using System.IO; public ...
- OC-NSArray
一.认识数组 oc中可以把NSObject对象的子类放到数组这个集合中,但是int.float.double等基础数据类型需要先进行转换才可以存入数组. oc中数组以NS开头,其中分为可变数组和不可变 ...
- New Concept English three(13)
1原文打字 32w/m 错词27个 After her husband had gone to work, Mrs Richards sent her children to school and w ...
- 概念:GNU构建系统和Autotool
经常使用Linux的开发人员或者运维人员,可能对configure->make->make install相当熟悉.事实上,这叫GNU构建系统,利用脚本和make程序在特定平台上构建软件. ...
- 我的第一个React自定义组件
今天随便翻了一下antd的组件库,看到下面这样的组件,当时我就震惊了: 这尼玛,这是出于什么样的考虑,一个列表还要用户编写子项的渲染方式. 所以,我就自己写了一个 List.js: List.less ...
- ajax请求-IE缓存处理
IE浏览器下使用GET发送请求时,如果两次请求的地址和参数相同,在不刷新页面的情况下,浏览器会缓存第一次的请求的内容,服务端更新后浏览器仍然显示第一次的内容 如在当前页面用户登录,在未登录的情况下,服 ...
- Unity 播放 带 alpha 通道的视频(Video Player组件)
孙广东 2017.6.18 http://blog.csdn.NET/u010019717 通常是 .webm类型文件!!!!! 你可以下载这个文件到本地: Http://tsubakit1.s ...