Portal -->bzoj2759

Solution

  哇我感觉这题真的qwq是很好的一题呀qwq

  很神qwq反正我真的是自己想怎么想都想不到就是了qwq

  

  首先先考虑一下简化版的问题应该怎么解决:

  1、如果说我知道\(x_1\equiv k_1*x_2+b_1(mod\ 10007)\),并且\(x_2\)已知,那么显然有当\(k_1=0\)时有\(x_1=x_2\);\(k_1=1\)且\(b_1=0\)时有无数组解,\(k_1=1\)且\(b_1\)不为\(0\)时无解;\(k_1>1\)时逆元求解(因为\(10007\)是质数嘛)

  2、如果说我知道\(x_1\equiv k_1*x_2+b_1(mod\ 10007)\)和\(x_2\equiv k_2*x_1+b_1(mod \ 10007)\),那么怎么求\(x_1\)呢

  有一种很粗暴的方法就是直接把第一条式子中的\(x_2\)用第二条式子的右边部分替换掉,然后直接解

​  

  然后我们可以想办法往这个方向靠

  我们来小小的转化一下这个问题,我们考虑把每一条式子\(x_i=k_i*x_{p_i}+b_i\),转化为由\(x_{p_i}\)向\(x_i\)连一条有向边,然后这样的话我们就可以得到一个。。基环外向树森林,大概是若干个长这个样子的东西(额当然这里没有把边的方向画出来):

  处理这样的东西,有一个比较套路的方法就是拆掉环上一条边然后变成树来维护处理

  我们选环上的其中一个点作为这块东西的\(rt\),然后将拆掉的那条边(某个点\(y\)指到\(rt\))对应的点\(y\)记为\(sp[rt]\),也就是\(rt\)的一个\(special\ father\)

  然后我们考虑用LCT来维护这个东西,但是具体维护什么呢

  

  这里有一个很神的想法,对于每一个splay上的节点,我们维护其子树内最左边的节点\(L\)(也就是深度最浅的那个)的\(sp\)表达最右边的那个节点\(R\)(深度最深的那个)的表达式的两个系数,也就是:
\[ x_{R}=k*x_L+b \]
  对于splay上的每个节点我们维护上面这个式子里面的\(k\)和\(b\)分别是多少(记作\(info[x].k\)和\(info[x].b\))

  这样一来,我们对于一个节点\(x_i\)做了\(access(x_i)\)以及\(splay(x_i)\)之后,\(info[x]\)中存的表达式其实就是:
\[ x_i=k*sp[rt]+b \]
  那么对于每次查询(记查询的那个点为\(x_a\)),我们需要做的就是用上面的操作得到\(x_i\)和\(sp[rt]\)之间的表达式,然后只要再得到\(sp[rt]\)关于自己的表达式我们就可以求出\(sp[rt]\)进而求得\(x_i\)了。后者的话因为根据定义\(sp[rt]\)应该是这棵树中的某个节点,所以我们直接用同样的\(access+splay\)操作就可以得到\(sp[rt]\)关于自己的表达式了

  然后对于修改的话,我们需要分类讨论一下(可以自己画个图理解一下就很清晰了)

1、\(rt=x\)

​  这里又可以再分两类

​  如果说\(p\)在这棵树中,那么修改\(sp[rt]\)即可;否则\(sp[rt]=0\)然后将\(rt\)接到\(p\)这个节点上面去,作为\(p\)的一个儿子

2、\(rt!=x\)

  不管别的首先我们都要将\(x\)和原来的\(fa[x]\)断开

​  如果说\(x\)在\(rt\)到\(sp[rt]\)的这个环上的话,断开之后会有一个影响,就是\(sp[rt]\)指向\(rt\)这条边不需要断开了,所以我们要将\(rt\)连到\(sp[rt]\)那里去作为其一个儿子

  然后不管是\(x\)是否在环上,我们都要判断如果说\(p\)在这棵树上,那么\(sp[x]=p\),否则\(sp[x]=0\)然后将\(x\)连到\(p\)那里去作为其一个儿子

  

​  这些都讨论完了之后,我们来想想这个关键的\(info[x]\)要怎么维护

  注意到这个在\(update\)的时候是必须按照一定顺序的,因为一个节点\(x\)的信息只能和原树中的\(fa[x]\)合并

  具体一点就是:
\[ \begin{aligned} x&=k_1*x_{fa}+b_1\\ x_{fa}&=k_2*x'+b_2\\ \\ \downarrow\\ \\ x&=k_1(k_2*x'+b_2)+b_1 \end{aligned} \]
  我们用\(ch[x][0]\)和\(ch[x][1]\)表示splay中\(x\)节点的左右儿子

​  假设我们现在知道\(info[ch[x][0]]]\)和\(info[ch[x][1]]\),我们想要得到\(info[x]\),那么其实只要先将\(info[ch[x][0]]\)表示的式子和\(x\)本身的式子先合并存为\(info[x]\),再将\(info[x]\)与\(info[ch[x][1]]\)合并即可,具体的话就是因为左子树中深度最深的节点在原树上就是\(fa[x]\),同理右子树中深度最浅的节点在原树上的\(fa\)就是\(x\),所以直接这么合并就好了

  

  想明白了的话还是挺好写的ovo(废话qwq然而我想了一天。。。)

​  

  代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=30010,MOD=10007,LCT=N;
struct Data{int k,b;Data(){}Data(int k1,int b1){k=k1; b=b1;}friend Data operator + (Data x,Data y){return Data(x.k*y.k%MOD,(x.b*y.k%MOD+y.b)%MOD);}
}val[N];
int h[N],vis[N],Fa[N],inv[N];
int n,m,tot,Cnt;
namespace Lct{/*{{{*/int ch[LCT][10],fa[LCT],sp[LCT];Data info[LCT];int tot;bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}int which(int x){return ch[fa[x]][1]==x;}void update(int x){//order is importantinfo[x]=val[x];if (ch[x][0]) info[x]=info[ch[x][0]]+info[x];if (ch[x][1]) info[x]=info[x]+info[ch[x][1]];}void rotate(int x){int dir=which(x),f=fa[x];if (!isroot(f)) ch[fa[f]][which(f)]=x;fa[x]=fa[f]; fa[f]=x;if (ch[x][dir^1]) fa[ch[x][dir^1]]=f;ch[f][dir]=ch[x][dir^1];ch[x][dir^1]=f;update(f); update(x);}void splay(int x){for (int f=fa[x];!isroot(x);f=fa[x]){if (!isroot(f))rotate(which(f)==which(x)?f:x);rotate(x);}}void access(int x){for (int last=0;x;last=x,x=fa[x]){splay(x);ch[x][1]=last;update(x);}}int get_rt(int x){access(x); splay(x);while (ch[x][0]) x=ch[x][0];return x;}void query(int x){Data tmp1,tmp2;access(x); splay(x);tmp1=info[x];//sp[rt]-->xint rt=get_rt(x);access(sp[rt]); splay(sp[rt]);tmp2=info[sp[rt]];//sp[rt]-->sp[rt]if (tmp2.k==1){if (tmp2.b==0) printf("-2\n");else printf("-1\n");}else{int valrt=inv[(1-tmp2.k+MOD)%MOD]*tmp2.b%MOD;printf("%d\n",(tmp1.k*valrt%MOD+tmp1.b)%MOD);}}void Cut(int x){access(x); splay(x);ch[x][0]=fa[ch[x][0]]=0;update(x);}bool InCir(int x,int y){//x in cir(y,sp[y])?access(sp[y]);splay(sp[y]);splay(x);return x==sp[y]||(!isroot(sp[y]));}void change(int x,int k,int p,int b){access(x);splay(x);val[x]=Data(k,b);update(x);int rt=get_rt(x);if (rt==x){if (get_rt(p)==rt) sp[x]=p;else sp[rt]=0,fa[rt]=p;}else{if (InCir(x,rt)){Cut(x);splay(rt);fa[rt]=sp[rt];sp[rt]=0;}elseCut(x);if (get_rt(p)==x)sp[x]=p;else sp[x]=0,fa[x]=p;}}
}/*}}}*/void prework(int x){vis[x]=Cnt;Lct::fa[x]=Fa[x];if (vis[Fa[x]]==Cnt){Lct::fa[x]=0;Lct::sp[x]=Fa[x];return;}prework(Fa[x]);
}void get_inv(int n){inv[1]=1;for (int i=2;i<=n;++i)inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
};int main(){/*{{{*/
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);
#endifchar op[5];int x,p,k,b;scanf("%d",&n);for (int i=1;i<=n;++i)scanf("%d%d%d",&val[i].k,&Fa[i],&val[i].b);get_inv(N-10);Cnt=0;for (int i=1;i<=n;++i)if (!vis[i])++Cnt,prework(i);scanf("%d",&m);for (int i=1;i<=m;++i){scanf("%s",op);if (op[0]=='A'){scanf("%d",&x);Lct::query(x);}else{scanf("%d%d%d%d%d",&x,&k,&p,&b);Lct::change(x,k,p,b);}}
}/*}}}*/

转载于:https://www.cnblogs.com/yoyoball/p/9311127.html

【bzoj2759】一个动态树好题相关推荐

  1. BZOJ2759 一个动态树好题

    题目 有\(N\)个未知数\(x[1..n]\)和\(N\)个等式组成的同余方程组: \(x[i]=k[i]*x[p[i]]+b[i] mod 10007\) 其中,\(k[i],b[i],x[i]∈ ...

  2. BZOJ 2759 一个动态树好题 (LCT)

    滚回来学文化课了-- 题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2759 题解 LCT,显然的做法是维护链上所有一次函数的复合. 如何 ...

  3. 树套树 ---- 树状数组套权值线段树模板题 P2617 Dynamic Rankings 动态第K大

    题目链接 题目大意: 给你一个数组aaa,aaa有两个操作 询问aaa中[l,r][l,r][l,r]区间里面第kkk小的数是哪个? 修改axa_xax​为yyy 解题思路: 首先我们知道权值线段树是 ...

  4. luoguP3690 【模板】Link Cut Tree (动态树)[LCT]

    题目背景 动态树 题目描述 给定N个点以及每个点的权值,要你处理接下来的M个操作.操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor ...

  5. 【BZOJ4372】烁烁的游戏 动态树分治+线段树

    [BZOJ4372]烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠. 题意: 给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠. 烁烁他每次会跳到一个节点u,把周围 ...

  6. 如何利用FineReport制作动态树报表

    在对数据字段进行分类管理时,利用动态树折叠数据是一个很好的方法,也就是点击数据前面的加号才展开对应下面的数据,如下图.那这样的效果在制作报表时该如何实现呢? 下面以报表工具FineReport为例介绍 ...

  7. 【动态树】[BZOJ2002] Bounce 弹飞绵羊

    实际上就是动态树的模版加上一个维护每一条链的size这样就可以吧一次弹射看成一条路径,然后统计这个路径上的size实际上就是经过了多少个节点然后没什么了.. #include <bits/std ...

  8. hdu1305 字典树水题

    题意:      给你一些字符串,然后问你他们中有没有一个串是另一个串的前缀. 思路:       字典树水题,(这种水题如果数据不大(这个题目不知道大不大,题目没说估计不大),hash下也行,把每个 ...

  9. P4719 【模板】“动态 DP“动态树分治(矩阵/轻重链剖分/ddp)

    P4719 [模板]"动态 DP"&动态树分治 求解树上最大权独立集,但是需要支持修改. https://www.luogu.com.cn/problem/solution ...

最新文章

  1. 从汗水物流到智慧物流,物流产业智能化
  2. break continue 016
  3. 【进程通信】Signal信号
  4. 【作业】第六章 面向对象基础
  5. java通过代码显示特定窗体,如何把这两段代码在一个窗体显示,类似于windows自带的扫雷一样...
  6. OpenCV运行自定义OCR模型
  7. 人才是培养的吗? (转)
  8. idea断点_IDEA Debug 无法进入断点的解决方法
  9. linux 创建一个垃圾篓防误删及其误删文件恢复
  10. 总结1-深度学习-基础知识学习
  11. 响应式下的雪碧图解决方案 - 活用background-size / background-position
  12. 异或运算符 判断奇偶
  13. 传智播客 C/C++学习笔记 数组和指针的关系, 字符串学习
  14. win10任务栏透明_谈谈我的Windows系统使用历程和win10桌面美化
  15. SCJP java主方法解释
  16. Oracle可视化工具plsqldev8.0安装详细步骤
  17. Xshell官网下载地址
  18. 虚拟机Ubuntut tftp服务不启动,service tftpd-hpa restart 失败的处理
  19. 新浪开放平台开发1--认证
  20. 云计算基础(二)—— 虚拟化

热门文章

  1. 【Spring5.x】对象的生命周期、配置文件参数化、自定义类型转换器、后置处理Bean
  2. 软件设计师24-算法
  3. 一步一坑学android之禁用Appt2(andriod studio3.0)
  4. String、StringBuffer、StringBuilder之间的区别 简明介绍
  5. Queue - 一种线程安全的FIFO实现
  6. Flask中数据库的应用
  7. 设计模式20_观察者
  8. 实例:供应商管理报表需求调研报告
  9. 小程序 php wecahtpay,PHP 微信公众号,小程序获取支付参数。微信支付
  10. centos系统mysql连接workbench