题目描述:

给出一棵n个节点的树,每个点初始m值为1。

你有三种操作:

1.Add l r k ,将l到r路径上所有点m值加k。

2.Multi l r k ,将l到r路径上所有点m值乘k。

3.Query l r ,设x是l到r路径上的点,y是x的m值。假设有1~y共y个点,随机打乱,求形成错排的概率。

(k<=1000,n<=80000)

题解:

树剖正解?

(反正我用的dfs序+并查集)

首先1000^80000错排怎么搞啊?

要明白我们真正要的并不是错排数,而是错排数/阶乘。

打表后发现他是:

0.0,0.5,0.333333333,0.375,0.366666667,0.368055556,0.367857143,0.367881944,0.367879464

最后一位用的一般值。

(后来发现这个精度依然不够,要用错排递推直接打表。不然会卡精。)

树链怎么修改啊?

其实可以用单点修改……

重点在于一共只有80000个点,如果m值超过15就不用处理了,保留15位就够了……

所以单点最多修改80000*15次……

并查集维护。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
//lgl AK in NOIp
#define N 80050
double num[],tmp[];
void init()
{
double now = ;
tmp[]=0.0,tmp[]=1.0;
num[]=0.5;
for(int i=;i<;i++)
{
now*=(double)i;
tmp[i]=(double)(i-)*(tmp[i-]+tmp[i-]);
num[i]=(double)tmp[i]/now;
}
}
int n,hed[N],cnt,q;
char ch[];
struct EG
{
int to,nxt;
}e[*N];
void ae(int ff,int t)
{
e[++cnt].to = t;
e[cnt].nxt = hed[ff];
hed[ff] = cnt;
}
struct aaafku
{
int s[*N];
void ins(int x,int d)
{
while(x<*N)
{
s[x]+=d;
x+=(x&(-x));
}
}
int qry(int x)
{
int ret = ;
while(x)
{
ret+=s[x];
x-=(x&(-x));
}
return ret;
}
}f[];
int las[N];
int dep[N],siz[N],fa[N],son[N],top[N],typ[N];
int tin[N],tout[N],tim;
void dfs1(int u,int ff)
{
tin[u]=++tim;
typ[u]=;
siz[u]=;
dep[u]=dep[ff]+;
las[u]=u;
f[].ins(tin[u],);
for(int j=hed[u];j;j=e[j].nxt)
{
int to = e[j].to;
if(to==ff)continue;
fa[to]=u;
dfs1(to,u);
siz[u]+=siz[to];
if(siz[to]>siz[son[u]])son[u]=to;
}
tout[u]=tim;
f[].ins(tout[u]+,-);
}
void dfs2(int u,int tp)
{
top[u] = tp;
if(!son[u])return ;
dfs2(son[u],tp);
for(int j=hed[u];j;j=e[j].nxt)
{
int to = e[j].to;
if(to!=fa[u]&&to!=son[u])
dfs2(to,to);
}
}
int get_lca(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
int get_las(int x)
{
if(las[x]==x)return x;
return las[x]=get_las(las[x]);
}
void deala(int u,int k,int lim)
{
if(dep[u]<=lim)return ;
f[typ[u]].ins(tin[u],-);
f[typ[u]].ins(tout[u]+,);
typ[u] = min(,typ[u]+k);
f[typ[u]].ins(tin[u],);
f[typ[u]].ins(tout[u]+,-);
deala(get_las(fa[u]),k,lim);
if(typ[u]==)las[u]=fa[u];
}
void dealb(int u,int k,int lim)
{
if(dep[u]<=lim)return ;
f[typ[u]].ins(tin[u],-);
f[typ[u]].ins(tout[u]+,);
typ[u] = min(,typ[u]*k);
f[typ[u]].ins(tin[u],);
f[typ[u]].ins(tout[u]+,-);
dealb(get_las(fa[u]),k,lim);
if(typ[u]==)las[u]=fa[u];
}
int main()
{
// freopen("yuyuko.in","r",stdin);
// freopen("yuyuko.out","w",stdout);
init();
scanf("%d",&n);
for(int ff,t,i=;i<n;i++)
{
scanf("%d%d",&ff,&t);
ae(ff,t),ae(t,ff);
}
dfs1(,),dfs2(,);
scanf("%d",&q);
for(int l,r,k,i=;i<=q;i++)
{
scanf("%s",ch+);
if(ch[]=='Q')
{
scanf("%d%d",&l,&r);
int lca = get_lca(l,r);
int ff = fa[lca];
double ans = 0.0;
for(int j=;j<;j++)
{
int sum = f[j].qry(tin[l])+f[j].qry(tin[r])-f[j].qry(tin[lca])-f[j].qry(tin[ff]);
ans+=(double)sum*num[j];
}
printf("%.1lf\n",ans);
}else
{
scanf("%d%d%d",&l,&r,&k);
int lca = get_lca(l,r);
if(ch[]=='A')
{
deala(las[l],k,dep[lca]);
deala(las[r],k,dep[lca]-);
}else
{
dealb(las[l],k,dep[lca]);
dealb(las[r],k,dep[lca]-);
}
}
}
return ;
}

最新文章

  1. js类型转换
  2. Character literal must contain exactly one character -- 一天一点小知识
  3. linux安装pip
  4. c++ 读取txt文件并输出到控制台
  5. 微信中修改title
  6. C#委托详解(3):委托的实现方式大全(续)
  7. (转)基于PHP的cURL快速入门
  8. JAXB 注解
  9. ListBox第一行字体比其他行小
  10. SSH框架整合 日志处理Spring结合 log4j、slf4j
  11. 上delloc 无呼叫 故障排除 笔记
  12. Java 年月日 日期加减
  13. My数据库和Ms数据库的区别
  14. python学习之路-书籍推荐
  15. ●Joyoi Dotp 驱逐猪猡
  16. [Harbor]Harbor简要介绍
  17. EF CodeFirst(四) 关系
  18. 微信小程序 - cb回调(typeof cb == &quot;function&quot; &amp;&amp; cb(obj);)
  19. Android 消息分发机制
  20. Python 数值计算库之-[Pandas](六)

热门文章

  1. 关于kafka-clients JAVA API的基本使用
  2. Ceph之PG数调整
  3. Word Cloud (词云) - Matlab
  4. springboot(七) 配置嵌入式Servlet容器
  5. Servlet,jsp,jsp的9大内置对象
  6. [UOJ386]鸽子固定器
  7. C++默认函数与函数重载
  8. 转 关于shell脚本中#!/bin/bash and #!/bin/ksh 的说明
  9. tomcat 修改端口
  10. jdk 1.8下 java ArrayList 添加元素解析