题目背景

盛夏,冰之妖精琪露诺发现了一大片西瓜地,终于可以吃到美味的冻西瓜啦。

题目描述

琪露诺是拥有操纵冷气程度的能力的妖精,一天她发现了一片西瓜地。这里有n个西瓜,由n-1条西瓜蔓连接,形成一个有根树,琪露诺想要把它们冷冻起来慢慢吃。

这些西瓜蔓具有神奇的性质,可以将经过它的冷气的寒冷程度放大或缩小,每条西瓜蔓放大/缩小冷气寒冷程度的能力值为Wi,表示冷气经过它后,寒冷程度值x会变为x*wi。每个西瓜也有一个寒冷程度值,炎热的夏日,所有西瓜的寒冷程度值初始都为0。

琪露诺会做出两种动作:

①.对着西瓜i放出寒冷程度为x的冷气。这股冷气顺着西瓜蔓向“西瓜树”的叶子节点蔓延,冷气的寒冷程度会按照上面的规则变化。遇到一个西瓜连了多条西瓜蔓时,每条叶子节点方向的西瓜蔓均会获得与原先寒冷程度相等的冷气。途径的所有西瓜的寒冷程度值都会加上冷气的寒冷程度值。

⑨.向你询问西瓜i的寒冷程度值是多少。

等等,为什么会有⑨?因为笨蛋琪露诺自己也会忘记放了多少冰呢。

所以,帮她计算的任务就这么交给你啦。

输入输出格式

输入格式:

第一行一个整数n,表示西瓜的数量。

西瓜编号为1~n,1为这棵“西瓜树”的根。

接下来n-1行,每行有两个整数u,v和一个实数w,表示西瓜u和西瓜v之间连接有一条藤蔓,它放大/缩小冷气寒冷程度的能力值为w。

接下来一行一个整数m,表示操作的数量。

接下来m行,每行两个或三个整数。

第一个数只能是1或9。

如果为1,接下来一个整数i和一个实数x,表示对西瓜i放出寒冷程度为x的冷气。

如果为9,接下来一个整数i,表示询问编号为i的西瓜的寒冷程度值。

输出格式:

对于每个操作⑨,输出一行一个实数,表示对应西瓜的寒冷程度值。

输入输出样例

输入样例#1:

4
1 2 1.00000000
2 3 0.00000000
3 4 1.00000101
9
1 1 3.00000000
9 2
9 3
1 2 1.42856031
9 4
9 2
1 3 4.23333333
9 2
9 4
输出样例#1:

3.00000000
0.00000000
0.00000000
4.42856031
4.42856031
4.23333761

说明

子任务可能出现如下的特殊性质:

“西瓜树”退化为一条链

输入数据中的实数均保留8位小数,选手的答案被判作正确当且仅当输出与标准答案误差不超过10^-7。请特别注意浮点数精度问题。

实际数据中,冷气的寒冷程度x的范围为 [-0.1,0.1]

(样例中的冷气寒冷程度的范围为[1,5])


20分代码

n<=1000  m<=1000

好小的树

--->朴素的、完全依照题意的遍历树算法

 #include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<cmath>
using namespace std; inline int read(){
int re=;
char ch;
bool flag=;
while((ch=getchar())!='-'&&(ch<''||ch>''));
ch=='-'?flag=:re=ch-'';
while((ch=getchar())>=''&&ch<='') re=(re<<)+(re<<)+ch-'';
return flag?-re:re;
} typedef long double lb; struct edge{
int to,next;
lb w;
edge(int to=,int next=,lb w=):
to(to),next(next),w(w){}
}; const int maxn=; const lb eps=1e-;
vector<edge> edges;
vector<edge> tree;
int n,m,cnt,root=;
int head[maxn],tmp_head[maxn];
lb data[maxn]; bool oo(lb ww){
if(fabs(ww)<eps) return ;
return ;
} inline void add_edge(int from,int to,lb w){
edges.push_back(edge(to,head[from],w));
head[from]=++cnt;
edges.push_back(edge(from,head[to],w));
head[to]=++cnt;
} inline void add_tree(int from,int to,lb w){
tree.push_back(edge(to,tmp_head[from],w));
tmp_head[from]=++cnt;
} void dfs_tree(int x,int fa){
for(int ee=head[x];ee;ee=edges[ee].next)
if(edges[ee].to!=fa){
add_tree(x,edges[ee].to,edges[ee].w);
dfs_tree(edges[ee].to,x);
}
} void dfs(int ss,lb ww){
data[ss]+=ww;
for(int ee=head[ss];ee;ee=tree[ee].next)
if(oo(tree[ee].w))
dfs(tree[ee].to,ww*tree[ee].w);
} int main(){
//freopen("temp.in","r",stdin);
cnt=;
n=read();
edges.push_back(edge(,,));
for(int i=;i<n;i++){
int from=read(),to=read();
lb w;scanf("%Lf",&w);
add_edge(from,to,w);
}
cnt=;
tree.push_back(edge(,,));
dfs_tree(root,);
swap(head,tmp_head);
m=read();
for(int i=;i<m;i++){
int op=read(),ss=read();
if(op&){
printf("%.8Lf\n",data[ss]);
}
else{
lb ww;scanf("%Lf",&ww);
dfs(ss,ww);
}
}
return ;
}

100分代码

...

2333333

我怎么这么傻。我的图论怎么这么弱呢

正解提供的思路是这样的

既然题目中有类似“从根到子树”的操作,可以很快地想到利用dfs序解决。好了就dfs序吧!然后把wi=0的边全部砍断,就得到了几棵互不关联的树。那么怎么砍断呢?只要将wi=0的边连向的点记录起来,分别从根(root=1)和这些被记录的节点做dfs序(走完一棵子树后序号不清零,要继续累加),就得到了我们需要的dfs序列。

维护dfs序的同时,维护一个k[]数组,ki表示从i节点所在子树的根到i节点一路上wi的累乘结果。

然后用树状数组(解决区间加和点询问问题的树状数组)维护所有节点。

对于操作①

  假如从一棵子树的根释放了冷气x,那么冷气一定到达这个子树的每一个节点,每一个节点i得到的冷气值就是ki*x,结合dfs序对表示这棵子树的区间加x就好了。那么对于一个普通节点i(非子树的根节点)释放的冷气x,就可以等同于从这棵子树根释放的冷气x/ki,对表示节点i的子树的dfs序中的一段加x/ki就好了。

  根据树状数组的性质时间复杂度为O(logn)

对于操作⑨

  操作①把重要的事都解决了,操作⑨只需要在树状数组上求出节点i得到的值x,输出x*ki即可。

  根据树状数组的性质时间复杂度为O(logn)

所以总的时间复杂度为O(mlogn),是可以解决问题的。

附上std的代码(5309ms)和我的代码(3954ms)。。良好的代码习惯可以压到2500-ms

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#define ld long double
using namespace std;
int n,m;
const ld eps=1e-;
vector<int>tab[];
vector<ld>val[];
ld k[];
ld tree[];
int ino[];
int outo[];
int fa[];
int tot=;
queue<int>q;
void add(int x,ld t)
{
for(x;x<=n;x+=x&-x)
tree[x]+=t;
}
ld query(int x)
{
ld res=;
for(x;x>;x-=x&-x)
res+=tree[x];
return res;
}
void dfs(int now,int father,long double ki)
{
ino[now]=++tot;
fa[now]=father;
k[now]=ki;
int sz=tab[now].size();
for(int i=;i<sz;++i)
{
int nex=tab[now][i];
if(nex==fa[now])continue;
if(fabs(val[now][i])<eps)
{
fa[nex]=now;
q.push(nex);
continue;
}
dfs(nex,now,ki*val[now][i]);
}
outo[now]=tot;
}
int main()
{
scanf("%d",&n);
for(int i=;i<n;++i)
{
int u,v;ld w;
scanf("%d%d%Lf",&u,&v,&w);
tab[u].push_back(v);
tab[v].push_back(u);
val[u].push_back(w);
val[v].push_back(w);
}
q.push();
while(!q.empty())
{
dfs(q.front(),fa[q.front()],1.0);
q.pop();
}
scanf("%d",&m);
while(m--)
{
int typ,i;
ld x;
scanf("%d",&typ);
if(typ==)
{
scanf("%d%Lf",&i,&x);
ld ins=x/k[i];
add(ino[i],ins);
add(outo[i]+,-ins);
}else{
scanf("%d",&i);
printf("%.8Lf\n",query(ino[i])*k[i]);
}
}
return ;
}

我的辣2333

 #include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
#include<cmath>
using namespace std; inline int read(){
char ch;
int re=;
bool flag=;
while((ch=getchar())!='-'&&(ch<''||ch>''));
ch=='-'?flag=:re=ch-'';
while((ch=getchar())>=''&&ch<='') re=(re<<)+(re<<)+ch-'';
return flag?-re:re;
} typedef long double ld;
typedef pair<int,int> PII; struct edge{
int to,next;
ld w;
edge(int to=,int next=,ld w=):
to(to),next(next),w(w){}
}; const int maxn=; vector<edge> edges;
int n,m,cnt=,root=,head[maxn],id[maxn],son[maxn];
ld kk[maxn],bit[maxn];
queue<PII> que; inline void add_edge(int from,int to,ld w){
edges.push_back(edge(to,head[from],w));
head[from]=++cnt;
edges.push_back(edge(from,head[to],w));
head[to]=++cnt;
} ld eps=1e-;
bool oo(ld w){
if(fabs(w)<eps) return ;
return ;
} void init(){
n=read();
edges.push_back(edge(,,));
for(int i=;i<n;i++){
int from=read(),to=read();
ld w;scanf("%Lf",&w);
add_edge(from,to,w);
}
} void dfs(int x,int fa,ld kkk){
id[x]=++cnt;
son[x]=;
kk[x]=kkk;
for(int ee=head[x];ee;ee=edges[ee].next)
if(edges[ee].to!=fa)
if(!oo(edges[ee].w))
que.push(make_pair(edges[ee].to,x));
else{
dfs(edges[ee].to,x,kkk*edges[ee].w);
son[x]+=son[edges[ee].to];
}
} ld getsum(int ss){
int sit=id[ss];
ld sum=;
while(sit<=n){
sum+=bit[sit];
sit+=sit&-sit;
}
return sum;
} void add_it(int sit,ld xx){
while(sit){
bit[sit]+=xx;
sit-=sit&-sit;
}
} void add(int left,int right,ld xx){
if(left-)
add_it(left-,-xx);
add_it(right,xx);
} void solve(){
m=read();
for(int i=;i<m;i++){
int op=read(),ss=read();
if(op&)
printf("%.8Lf\n",getsum(ss)*kk[ss]);
else{
ld xx;scanf("%Lf",&xx);
add(id[ss],id[ss]+son[ss]-,xx/kk[ss]);
}
}
} int main(){
//freopen("temp.in","r",stdin);
init();
que.push(make_pair(root,));
cnt=;
while(!que.empty()){
PII x=que.front(); que.pop();
dfs(x.first,x.second,1.0);
}
solve();
return ;
}

[luogu P3787][新创无际夏日公开赛] 冰精冻西瓜 [树状数组][dfs序]的更多相关文章

  1. luogu SP8093 后缀自动机+树状数组+dfs序

    这题解法很多,简单说几个: 1. 线段树合并,时间复杂度是 $O(nlog^2n)$ 的. 2. 暴力跳 $fail,$ 时间复杂度 $O(n\sqrt n),$ 比较暴力. 3. 建立后缀树后在 $ ...

  2. 【Luogu P5168】xtq玩魔塔(Kruskal 重构树 & 树状数组 & set)

    Description 给定一个 \(n\) 个顶点,\(m\) 条边的无向联通图,点.边带权. 先有 \(q\) 次修改或询问,每个指令形如 \(\text{opt}\ x\ y\): \(\tex ...

  3. BZOJ 2434 Luogu P2414 [NOI2011]阿狸的打字机 (AC自动机、树状数组)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2434 题解: 我写的是离线做法,不知道有没有在线做法. 转化一波题意,\(x\)在AC ...

  4. [洛谷 P3787] 冰精冻西瓜

    题目描述 琪露诺是拥有操纵冷气程度的能力的妖精,一天她发现了一片西瓜地.这里有n个西瓜,由n-1条西瓜蔓连接,形成一个有根树,琪露诺想要把它们冷冻起来慢慢吃. 这些西瓜蔓具有神奇的性质,可以将经过它的 ...

  5. 冰精冻西瓜[P3787洛谷]

    题目描述 琪露诺是拥有操纵冷气程度的能力的妖精,一天她发现了一片西瓜地.这里有n个西瓜,由n-1条西瓜蔓连接,形成一个有根树,琪露诺想要把它们冷冻起来慢慢吃. 这些西瓜蔓具有神奇的性质,可以将经过它的 ...

  6. Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分)

    Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分) Description L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之 ...

  7. Luogu 45887 全村最好的嘤嘤刀(线段树 树状数组)

    https://www.luogu.org/problemnew/show/T45887 题目背景 重阳节到了,我们最好的八重樱拥有全村最好的嘤嘤刀…… 题目描述 在绯玉丸力量的影响下,八重村成了一条 ...

  8. luogu P1972 [SDOI2009]HH的项链 |树状数组 或 莫队

    题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH 不断地收集新的贝壳,因此,他的项链变得越来越长. ...

  9. luogu P3031 [USACO11NOV]高于中位数Above the Median (树状数组优化dp)

    链接:https://www.luogu.org/problemnew/show/P3031 题面: 题目描述 Farmer John has lined up his N (1 <= N &l ...

随机推荐

  1. C#解析json的两种方式

    C#中Json转换主要使用的几种方法! 这篇主要介绍2.4.第三种方法使用的比较局限,所以我没有深入学习. 第二种方法 我使用比较多的方式,这个方法是.NET内置的,使用起来比较方便 A.利用seri ...

  2. IIC协议学习笔记

    "移植"的重要性:并非所有的电路都得自己设计,到了一定阶段,"移植"也是一种学习能力.--CrazyBingo 转眼间期末又到了,最近开始了所谓的期末总预习,比 ...

  3. RELabel : 一个极简的正则表达式匹配和展示框架

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  4. 学习总结------用JDBC连接MySQL

    1.下载MySQL的JDBC驱动 地址:https://dev.mysql.com/downloads/connector/ 为了方便,直接就选择合适自己的压缩包 跳过登录,选择直接下载 下载完成后, ...

  5. Discuz搜索改为指向帖子

    安装的版本是DiscuzX2.5,搜索的时候发现默认指向的是门户里的文章搜索,但程序都没有安装门户,只有论坛,所以不能搜索文章. 在网上找了半天终于找到修改的办法了. <input name=& ...

  6. JAVA优雅停机的实现

    最近在项目中需要写一个数据转换引擎服务,每过5分钟同步一次数据.具体实现是启动engine server后会初始化一个ScheduledExecutorService和一个ThreadPoolExec ...

  7. NoSQL数据库:Redis适用场景及产品定位

    传统MySQL+ Memcached架构遇到的问题 实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量 ...

  8. Ext 创建workspace package

    Ext 创建workspace package Package ExtJs Project 1. 创建工作区间文件目录 md wpt 2. 进入目录 cd wpt 3. 创建 创建工作区间 sench ...

  9. Django开发的基于markdown的博客开源

    PiperMarkdown Blog for Django1.11,Python 3.6,based on Markdown,网址,希望大家能给个star,谢谢! 什么是PiperMarkdown 这 ...

  10. [图形学] Chp10 OpenGL三维观察程序示例

    10.10节书中给出了一个程序示例,有一个填充正方形,从侧面的角度观察并画到屏幕上. 图0 这里进一步画出一个立方体,将相机放入立方体中心,旋转相机,达到在立方体中旋转看到不同画面的效果. 步骤: 1 ...