UOJ 418 【集训队作业2018】三角形——思路+线段树合并
看了题解才会……
很好的想法是把整个过程看成若干 “取一点 i ,值+=w[ i ],值-=\(\sum w[j]\)”(其中 j 是 i 的孩子)的操作组成的序列。
序列有一个限制是 “孩子的操作在父亲前面” 。把序列反一下,操作变成 “取一点 i , 值-=w[ i ],值+=\(\sum w[j]\)” ,每个点就只被其父亲的位置限制了,比较好做。
用 ( x, y ) 表示一个点的操作。 x 表示操作结束的增量, y 表示过程中最大值与初始值的差。之所以是“与初始值的差”,是为了今后合并两个操作;因为初始值不确定。
每个点的初值就是 ( \(-w[i]+\sumw[j],\sumw[j]\) )。合并 ( a, b ) 、( c, d ) 之后会变成 ( a+c , max( b, a+d ) ) 。
可以贪心地确定每个点的操作处在序列的什么位置。方法就是尝试交换相邻位置。
发现:1.同时 x<0 ,先做 y 大的;
2.同时 x>=0 ,先做 y-x 小的;
3.x<0 先于 x>=0
用堆维护,每次找最优先的。如果要做这个点的时候,其父亲还没做,就把它和父亲合并在一起放入堆,表示做完父亲就做它。可以用并查集+链表维护一个整体内部的操作顺序。
注意 x , y 相同的要按 id 区分开;都是 x<0 而 y , id 相同的要按 x 的具体值区分开。否则删除堆无法正常工作。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
#define ls Ls[cr]
#define rs Rs[cr]
using namespace std;
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;
}
ll Mx(ll a,ll b){return a>b?a:b;}
ll Mn(ll a,ll b){return a<b?a:b;}
const int N=2e5+;
int n,yf[N],w[N],fa[N],p[N],dy[N],tot; bool vis[N];
int hd[N],mn[N],xnt,to[N<<],nxt[N<<],tp[N],tt; ll ans[N];
int pr[N],nt[N],st[N],en[N];
struct Node{
ll x,y; int id;
Node(ll x=,ll y=,int i=):x(x),y(y),id(i) {}
Node operator+ (const Node &b)const
{return Node(x+b.x,Mx(y,x+b.y),id);}
bool operator< (const Node &b)const
{
if(x<&&b.x>=)return false; if(x>=&&b.x<)return true;
if(x<&&b.x<)
{
if(y!=b.y)return y>b.y;
if(id!=b.id)return id<b.id;
return x<b.x;
}
if(y-x!=b.y-b.x)return y-x<b.y-b.x;
if(id!=b.id)return id<b.id;
return x<b.x;
}
bool operator== (const Node &b)const
{ return x==b.x&&y==b.y&&id==b.id;}
}a[N],ya[N];
priority_queue<Node> q,dq;
namespace T{
const int M=N*;
int tot,rt[N],Ls[M],Rs[M]; Node vl[M];
int nwnd(int pr=)
{
int cr=++tot; ls=Ls[pr]; rs=Rs[pr];
vl[cr]=vl[pr]; return cr;
}
void build(int l,int r,int &cr,int ps)
{
cr=nwnd(); if(l==r){vl[cr]=ya[p[l]];return;}
int mid=l+r>>;
if(ps<=mid)build(l,mid,ls,ps);
else build(mid+,r,rs,ps);
vl[cr]=vl[ls]+vl[rs];
}
void mrg(int l,int r,int &cr,int pr)
{
if(!pr)return; if(!cr){cr=pr;return;}//use is ok
if(l==r){vl[cr]=vl[cr]+vl[pr];return;}
int mid=l+r>>;
mrg(l,mid,ls,Ls[pr]); mrg(mid+,r,rs,Rs[pr]);
vl[cr]=vl[ls]+vl[rs];
}
void dfs(int cr)
{
build(,n,rt[cr],dy[cr]);
for(int i=hd[cr],v;i;i=nxt[i])
{
dfs(v=to[i]);
mrg(,n,rt[cr],rt[v]);
}
ans[cr]=w[cr]+vl[rt[cr]].y;
}
}
void add(int x,int y)
{to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void frs()
{
while(dq.size()&&dq.top()==q.top())
q.pop(), dq.pop();
}
int fnd(int a){ return fa[a]==a?a:fa[a]=fnd(fa[a]);}
void mrg(int x,int y)
{
if(fa[y]==x)exit();
pr[st[y]]=en[x]; nt[en[x]]=st[y]; en[x]=en[y];
dq.push(a[x]); a[x]=a[x]+a[y]; q.push(a[x]);
fa[y]=x; mn[x]=Mn(mn[x],mn[y]);
}
void solve(int x)
{
int cr=st[x];
while(cr)
{
p[++tot]=cr;dy[cr]=tot;vis[cr]=;cr=nt[cr];
}
}
int main()
{
int op=rdn(); n=rdn();
for(int i=;i<=n;i++)yf[i]=rdn(),add(yf[i],i);
for(int i=;i<=n;i++)w[i]=rdn();
for(int i=n;i;i--)
{
a[i].x=a[i].y-w[i]; a[yf[i]].y+=w[i];
a[i].id=i; fa[i]=i; mn[i]=i;
q.push(a[i]); ya[i]=a[i]; st[i]=en[i]=i;
}
vis[]=;
while(q.size())
{
frs(); if(!q.size())break;
Node k=q.top(); q.pop(); int x=k.id;
if(vis[yf[mn[x]]]){solve(x);continue;}
mrg(fnd(yf[mn[x]]),x);
}
/*for(int i=1;i<=tot;i++)printf("%d ",p[i]);puts("");
for(int i=1;i<=tot;i++)printf("%d ",dy[i]);puts("");*/
T::dfs();
for(int i=;i<=n;i++)printf("%lld ",ans[i]);
puts(""); return ;
}
UOJ 418 【集训队作业2018】三角形——思路+线段树合并的更多相关文章
- uoj#418. 【集训队作业2018】三角形(线段树合并)
传送门 好迷啊--膜一下ljz 考虑每个操作,如果把操作按先后顺序放到序列上的话,操作一就是把\(w_i\)的石子放到某个节点,那么就是在序列末端加入\(w_i\),然后根据贪心肯定要把它所有儿子的石 ...
- [集训队作业2018]蜀道难——TopTree+贪心+树链剖分+链分治+树形DP
题目链接: [集训队作业2018]蜀道难 题目大意:给出一棵$n$个节点的树,要求给每个点赋一个$1\sim n$之内的权值使所有点的权值是$1\sim n$的一个排列,定义一条边的权值为两端点权值差 ...
- LOJ #2537. 「PKUWC 2018」Minimax (线段树合并 优化dp)
题意 小 \(C\) 有一棵 \(n\) 个结点的有根树,根是 \(1\) 号结点,且每个结点最多有两个子结点. 定义结点 \(x\) 的权值为: 1.若 \(x\) 没有子结点,那么它的权值会在输入 ...
- UOJ#397. 【NOI2018】情报中心 线段树合并 虚树
原文链接www.cnblogs.com/zhouzhendong/p/UOJ397.com 前言 这真可做吗?只能贺题解啊-- 题解 我们称一条路径的 LCA 为这条路径两端点的 LCA. 我们将相交 ...
- UOJ#435. 【集训队作业2018】Simple Tree 树链剖分,分块
原文链接www.cnblogs.com/zhouzhendong/p/UOJ435.html 前言 分块题果然是我这种蒟蒻写不动的.由于种种原因,我写代码的时候打错了很多东西,最致命的是数组开小了.* ...
- uoj #450[集训队作业2018]复读机
传送门 \(d=1\),那么任何时刻都可以\(k\)个复读机的一种,答案为\(k^n\) \(d>1\),可以枚举某个复读机的复读次数(必须是\(d\)的倍数),然后第\(i\)个复读时间为\( ...
- UOJ 422 [集训队作业2018] 小Z的礼物 min-max容斥 期望 轮廓线dp
LINK:小Z的礼物 太精髓了 我重学了一遍min-max容斥 重写了一遍按位或才写这道题的. 还是期望多少时间可以全部集齐. 相当于求出 \(E(max(S))\)表示最后一个出现的期望时间. 根据 ...
- UOJ#418. 【集训队作业2018】三角形
#418. [集训队作业2018]三角形 和三角形没有关系 只要知道儿子放置的顺序,就可以直接模拟了 记录历史最大值 用一个pair(a,b):之后加上a个,期间最大值为增加b个 合并? A1+A2= ...
- UOJ #449. 【集训队作业2018】喂鸽子
UOJ #449. [集训队作业2018]喂鸽子 小Z是养鸽子的人.一天,小Z给鸽子们喂玉米吃.一共有n只鸽子,小Z每秒会等概率选择一只鸽子并给他一粒玉米.一只鸽子饱了当且仅当它吃了的玉米粒数量\(≥ ...
随机推荐
- zookeeper centos分布式安装使用
1. 请先安装jdk和下载zookeeper.ssh免密登录请自行配置.大家可以到官网下载或我的网盘. 网盘地址: 共3台机器c0,c1,c2 192.168.132.148 c0192.168.13 ...
- python web自动化测试框架搭建(功能&接口)——通用模块
1.通用模块: config.conf: 公共配置文件,配置报告.日志.截图路径,以及邮件相关配置 [report] reportpath = E:\workspace\WebAutomation\s ...
- Centos安装GD库
tar zxvf ncurses-5.6.tar.gz 进入目录 cd ncurses-5.6 生成 makefile文件,再进一步编译 ./configure --prefix=/usr --wit ...
- Java IO(2)
关于流的概念 Java 由流来完成具体的IO操作,虽然面对的是不同的外设(网络.鼠标.键盘)IO流使用与全部的外设,在底层Java已经将具体与物理设备交互的细节都处理好了. 流的分类: 从功能上 输入 ...
- < python PIL - 批量图像处理 - RGB图像生成灰度图像 >
< python PIL - 批量图像处理 - RGB图像生成灰度图像 > 直接用python自带的PIL图像库,将一个文件夹下所有jpg/png的RGB图像转换成灰度/黑白图像 from ...
- Eclipse Kepler安装WST Server Adapter后创建Server无Tomcat解决方法
在Eclipse Kepler下安装完WST Server Adapter后,创建Server时发现没有Tomcat服务器的选项,这个问题解决起来很简单, 只需要安装一下JST Server Adap ...
- Codeforces 1148C(思维)
题面 给出一个长度为n的排列a,每次可以交换序列的第i个和第j个元素,当且仅当\(2 \times |i-j| \geq n\),求一种交换方案,让序列从小到大排好序 分析 重点是考虑我们怎么把第x个 ...
- 对于nginx配置文件中的fastcgi_param相关参数的理解
今天在ubuntu中搭建LNMP的时候,遇到了一个问题 在浏览器中访问.php文件的时候,nginx不能正常解析,页面只是空白,后来百度了一下,发现了问题 在nginx的配置文件nginx.conf中 ...
- 使用git、git-flow与gitlab工作
使用git.git-flow与gitlab工作 1. 摘要 在工作中使用git代替svn也有一段时间了,对于git的一些特性喜爱的同时也一直遇到相同的问题:“这时候应该打什么命令?”.相对于svn或者 ...
- Nginx学习总结:proxy与rewrite模块(三)
斜体下划线,表示建议采用默认配置,无需显式的配置 一.ngx_http_upstream_module 此模块中可配置的指令并不是很多.nginx的负载均衡算法包括: 1)round-robin:轮询 ...