T1:还在头铁,顺便复习了一下lct【虽然这题用不上因为复杂度不对】

头铁结束。

虽然题目存在换根的操作,实际上并不用真的换根。

2操作中求lca的时候只要考虑原树上root和x、y的lca以及x,y的lca,三个中取最深的就是现树上x和y的lca。

关于u的子树整体操作需要分类讨论。如果现根不在原树上u的子树里,那么在新树上的目标子树与原树相同,直接操作。如果u就是root,那么直接整棵树都操作。最后如果root在原树上u子树里,那么需要反一下,应当进行操作的部分是整棵树上除了u包含root的这棵子树的所有部分。

查询操作同理。

树上一棵子树的整体加减可以利用树剖解决。一整棵子树对应在线段树上是一段连续区间。

#include<iostream>
#include<cstdio>
using namespace std;
int n,q,a[],root=,t;
int ver[],Next[],head[],tot;
int siz[],dep[],son[],rec[],rec1[];
int fa[],lip[],cnt;
void add(int x,int y){
ver[++tot]=y;
Next[tot]=head[x];
head[x]=tot;
}
struct node{
int l,r;
long long sum,tag;
}b[*];
void dfs(int x,int f){
siz[x]=;
for(int i=head[x];i;i=Next[i]){
int y=ver[i];
if(y==f)continue;
dep[y]=dep[x]+;
fa[y]=x;
dfs(y,x);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]])son[x]=y;
}
}
void dfs1(int x,int upp){
lip[x]=upp;
rec[x]=++cnt;
rec1[cnt]=x;
if(!son[x])return;
dfs1(son[x],upp);
for(int i=head[x];i;i=Next[i]){
int y=ver[i];
if(y==fa[x]||y==son[x])continue;
dfs1(y,y);
}
}
void build(int p,int l,int r){
b[p].l=l,b[p].r=r;
if(l==r){
b[p].sum=a[rec1[l]];
return;
}
int mid=(l+r)/;
build(p*,l,mid);
build(p*+,mid+,r);
b[p].sum=b[p*].sum+b[p*+].sum;
}
int lca(int x,int y){
while(lip[x]!=lip[y]){
if(dep[lip[x]]<dep[lip[y]])swap(x,y);
x=fa[lip[x]];
}
if(dep[x]>dep[y])return y;
else return x;
}
int lca1(int x,int y){
while(lip[x]!=lip[y]){
if(fa[lip[y]]==x)return lip[y];
y=fa[lip[y]];
}
return rec1[rec[x]+];
}
void pushdown(int p){
if(b[p].tag){
b[p*].tag+=b[p].tag;
b[p*].sum+=(b[p*].r-b[p*].l+)*b[p].tag;
b[p*+].tag+=b[p].tag;
b[p*+].sum+=(b[p*+].r-b[p*+].l+)*b[p].tag;
b[p].tag=;
}
}
void change(int p,int l,int r,long long y){
if(l<=b[p].l&&b[p].r<=r){
b[p].sum+=(b[p].r-b[p].l+)*y;
b[p].tag+=y;
return;
}
pushdown(p);
int mid=(b[p].l+b[p].r)/;
if(l<=mid)change(p*,l,r,y);
if(r>mid)change(p*+,l,r,y);
b[p].sum=b[p*].sum+b[p*+].sum;
}
long long ask(int p,int l,int r){
if(l<=b[p].l&&b[p].r<=r){
return b[p].sum;
}
pushdown(p);
int mid=(b[p].l+b[p].r)/;
long long val=;
if(l<=mid)val+=ask(p*,l,r);
if(r>mid)val+=ask(p*+,l,r);
b[p].sum=b[p*].sum+b[p*+].sum;
return val;
}
int main(){
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
scanf("%d%d",&n,&q);
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=,x,y;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs(,);
dfs1(,);
build(,,n);
// scanf("%d",&q);
for(int i=,opt,x,y;i<=q;i++){
long long z;
scanf("%d",&opt);
if(opt==){
scanf("%d",&x);
root=x;
}
else if(opt==){
scanf("%d%d%lld",&x,&y,&z);
int x1=lca(x,y);
t=x1;
int x2=lca(x,root);
if(dep[x2]>dep[t])t=x2;
int x3=lca(y,root);
if(dep[x3]>dep[t])t=x3;
if(lca(t,root)!=t){//t原子树
change(,rec[t],rec[t]+siz[t]-,z);
}
else if(t==root){
b[].sum+=n*z;
b[].tag+=z;
}
else{
b[].sum+=n*z;
b[].tag+=z;
int t1=lca1(t,root);
change(,rec[t1],rec[t1]+siz[t1]-,-z);
}
}
else{
scanf("%d",&x);
t=x;
if(lca(t,root)!=t){//t原子树
printf("%lld\n",ask(,rec[t],rec[t]+siz[t]-));
}
else if(t==root){
printf("%lld\n",b[].sum);
}
else{
long long val=b[].sum;
int t1=lca1(t,root);
val-=ask(,rec[t1],rec[t1]+siz[t1]-);
printf("%lld\n",val);
}
}
}
return ;
}

T2:Function

看到题目里的递推式,莫名其妙先画了个网格,横x轴纵y轴。

然后发现第一排是a1的各个倍数,第一列是ai自己。然后根据相邻两个a的大小关系好像可以推路径。

然后写暴力打了个表,按普通的行列输出,发现自己这部分想麻烦了。似乎前面小的ai可以斜着连过来覆盖现在的ai,一列会分段被多个ai覆盖。然后感觉有点像决策单调性【什么】,试图从前面转移。

然后考虑给一列打标记,在哪个x开始被前面的哪个a覆盖,然后每一列从上一列转移这个标记。然后发现中间有断层,行不通。

这个时候重新开始想之前发现的斜着连过来这一块,一个(x,y)可以先向之前的ai的列去走,然后到某一列一直走到顶。

于是怎么找这个ai?

把走到ai这列得出的答案列了个式子:ai*(x-y)+s[y]-s[i]+i*a[i]。假设从(x,y)往回一直走到第一列,还剩下x-y步到顶,这部分一定要填ai。然而ai不一定是第一列,多往回走几列就少让ai累加了多少行,再把这部分补上。以及第一行就是ai本身而不是从0开始所以相当于ai多累加一行。

对于一个询问,sy是不变的,所以先去掉。发现剩下的这部分式子是一个关于x-y的一次函数。假设a=ai,b=-s[i]+i*a[i]。

我对斜率优化不熟…在这里开始懵逼了,最后强行头铁出了单调栈这一步但是写不完了。

/*(注释掉了)

推出一次函数以后,考虑ai比aj优的条件。两个式子用不等式算一下得出i比j优的条件是(bj-bi)/(ai-aj)>(x-y),两个ai覆盖的交点也可以这样得到。

维护一个下凸包,斜率递增。

观察打好的表发现,覆盖同一列y的ai从靠近y的地方递减。离y远而a更大的ai没有再做贡献的可能性,即作贡献的ai递减。

所以可以用单调栈维护。询问的时候在凸壳上二分x的位置。

*/

出锅了出锅了,方法没锅思路有锅。

之前有点强行解释的嫌疑。实际上得出一堆一次函数以后,因为我们只考虑这些一次函数的最小值,所以才会去维护一个上凸包。

上凸包!!被机房大佬无情嘲笑。画张图一看我脑子里这就是个上凸包…

用两个点的函数式进行比较的函数单纯只是为了维护这个凸包而已和什么x的覆盖到底有没有关系我也搞不清。但是不用这种写法,老老实实在凸包上二分,当然完全是正确的。

二次补充:

的确是上凸包,这个没问题。

每次到新的一列加一条直线,其实是加了一条从原点开始斜率ai的直线。因为每次转移到下一列的时候凸包其实整体向右和向上平移了【可能就是我前面发现的多端覆盖标记的后移】,所以对于新加入的这条原点开始的直线来说,它能ban掉所有之前的斜率比它大的直线,即aj>ai且j<i的直线。

这就是弹出大于当前ai的a值的意义。

而后面利用函数比较而弹栈的操作,有一种更好理解的做法【也许等价?】:解方程得栈顶与新加入直线的交点以及栈顶与前一条直线的交点,弹掉所有会让凸包交点不单调的直线。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,q,cnt=;
long long a[],sum[],b[],ans[];
double num[];
int t[],p;
struct node{
int x,y,id;
}que[];
bool cmp(node a,node b){
if(a.y==b.y)return a.x<b.x;
else return a.y<b.y;
}
double get(int x,int y){
return (double)(b[y]-b[x])/(double)(a[x]-a[y]);
}
int main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%lld",&a[i]);
sum[i]=sum[i-]+a[i];
b[i]=i*a[i]-sum[i];
}
scanf("%d",&q);
for(int i=;i<=q;i++){
scanf("%d%d",&que[i].x,&que[i].y);
que[i].id=i;
}
sort(que+,que+q+,cmp);
for(int i=;i<=n;i++){
while(p&&a[t[p]]>=a[i])p--;
while(p>=&&get(i,t[p])>get(t[p],t[p-]))p--;
t[++p]=i;
if(p>)num[n-p]=get(i,t[p-]);
while(que[cnt].y==i){
int x=lower_bound(num+n-p,num+n-,(que[cnt].x-que[cnt].y))-num;
x=n-x;
ans[que[cnt].id]=a[t[x]]*(que[cnt].x-que[cnt].y)+b[t[x]]+sum[que[cnt].y];
cnt++;
}
}
for(int i=;i<=q;i++){
printf("%lld\n",ans[i]);
}
return ;
}

有些地方自己也不是很明白,再找一点斜率优化的题写…

二次补充结束,终于算是全搞明白了……

T3:什么FT?FF什么?F什么T?

因为头铁T2而挂掉了的考试,最后发现T2其实我也没推出来多少,主要是自创斜率优化【指不熟斜率优化】的操作属实弟中弟。

今天没有考试,但我改不完【迫真】

2019.9.24 csp-s模拟测试51(a) 反思总结的更多相关文章

  1. 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组

    2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...

  2. 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色

    2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...

  3. 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)

    2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...

  4. 2019.10.24 CSP%你赛第二场d1t3

    题目描述 Description 精灵心目中亘古永恒的能量核心崩溃的那一刻,Bzeroth 大陆的每个精灵都明白,他们的家园已经到了最后的时刻.就在这危难关头,诸神天降神谕,传下最终兵器——潘少拉魔盒 ...

  5. [考试反思]0924csp-s模拟测试51:破碎

    总参赛人数:15 有点菜. 不知道是撞了什么大运没有滚出A层. 但是一回到A层就暴露出了一个大问题:码速. 不是调试速度,,就是纯粹码的速度... 边讲考试状态边说吧... 上来肝T1.一看,是个换根 ...

  6. CSP-S 模拟测试 51 题解

    考试过程: 惯例先看一遍三道题,T1 一开始反应要求割点,但是这是有向图,肯定不能求割点,康了一下数据范围,有40%是树的,还不错,决定待会在打. 看T2 字符串题,完了我字符串最弱了,肯定只能打暴力 ...

  7. [CSP-S模拟测试51]题解

    错失人生中第一次AK的机会…… A.attack 支配树板子题.考场上发明成功√ 首先支配树上两点路径之间的点都是必经之点,根据这个性质我们就可以yy出建树的方法.跑拓扑,在每个点(设为$x$)即将入 ...

  8. csp-s模拟测试51(b)attack,tree题解

    题面:https://www.cnblogs.com/Juve/articles/11598286.html attack: 支配树裸题? 看一下支配树是什么: 问题:我们有一个有向图(可以有环),定 ...

  9. 2019.10.20 csp-s模拟测试 lrd试题 反思总结

    赶进度赶进度,丢个代码两三句备注一下完事了. day1: 前面两道题没实际写代码怕印象不深所以描述一下大意. T1: 题目大意:给出两个数&.|.^的结果(可能只给出其中某一项或者某两项),求 ...

随机推荐

  1. Joomla - 模块系统(新建模块、模块类别、自定义模块)

    Joomla - 模块系统,模块配合模板的布局设置.菜单分配.权限分配能创建出一个内容丰富且易于管理的高度自定义前端页面架构 一.新建模块 进入后台,点击顶栏菜单 扩展管理 -> 模块管理 ,进 ...

  2. 19-11-05-Night

    我就是不行. ZJ: 好像是因为郁闷了才咕掉的…… 33 Miemeng 30 00:01:34 40 00:01:46 0 00:01:22 70 00:01:46 不记得当时怎么想的 T1只会暴力 ...

  3. java中自己对页面跳转问题的一些经验

    在eclipse中,如果你要在jsp页面跳转到servlet页面中,可以用action=“/根文件名/servlet文件名” 的方式跳转. 例如我创建了一个web application名字是test ...

  4. 关于获取webview(窗口间关系)的方法

    1.获取指定页面ID的webview plus.webview.getWebviewById('为页面设置的id值'): 该方法主要用于首页底部导航切换到子页面时不执行子页面的函数,因为在设置导航的时 ...

  5. centos7下Elasticsearch5.2.2和head 插件环境搭建

    ElasticSearch是一个基于Lucene构建的开源,分布式,RESTful搜索引擎.设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便.支持通过HTTP使用JSON进行数据索引 ...

  6. eclipse中使用lombok不生效

    eclipse中使用lombok,在实体类中添加@Data后,还是不能调用get.set方法.需要修改eclipse配置 1.将 lombok.jar 复制到eclipse.ini同级目录.下载的lo ...

  7. 第一个简单netty程序

    一个简单的netty的程序,主要是netty的客户端和服务端通信. 大部分说明都写在代码注释中 netty server TimeServer import io.netty.bootstrap.Se ...

  8. java线程队列

    工作原理 1.线程池刚创建时,里面没有一个线程.任务队列是作为参数传进来的.不过,就算队列里面有任务,线程池也不会马上执行它们. 2.当调用 execute() 方法添加一个任务时,线程池会做如下判断 ...

  9. RTNETLINK answers: File exists错误解决方法

    >一.写在前面: 因为是我刚学习linux好多问题需要解决,bolg仅作为记录自己的在技术这条道路上的点点滴滴. 二.事件起因: 最近因为女友的原因消沉的好长时间,在马哥那里的课程的结束到现在已 ...

  10. [计蒜客] 矿石采集【记搜、Tarjan缩点+期望Dp】

    Online Judge:计蒜客信息学3月提高组模拟赛 Label:记搜,TarJan缩点,树状数组,期望Dp 题解 整个题目由毫无关联的两个问题组合成: part1 问题:对于每个询问的起点终点,求 ...