2759: 一个动态树好题

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 772  Solved: 258
[Submit][Status][Discuss]

Description

有N个未知数x[1..n]和N个等式组成的同余方程组:
x[i]=k[i]*x[p[i]]+b[i] mod 10007
其中,k[i],b[i],x[i]∈[0,10007)∩Z
你要应付Q个事务,每个是两种情况之一:
一.询问当前x[a]的解
A a
无解输出-1
x[a]有多解输出-2
否则输出x[a]
二.修改一个等式
C a k[a] p[a] b[a]

Input

N 下面N行,每行三个整数k[i] p[i] b[i]
Q 下面Q行,每行一个事务,格式见题目描述

Output

对每个询问,输出一行一个整数。
对100%的数据,1≤N≤30000,0≤Q≤100000,时限2秒,其中询问事务约占总数的80%

Sample Input

5
2 2 1
2 3 2
2 4 3
2 5 4
2 3 5
5
A 1
A 2
C 5 3 1 1
A 4
A 5

Sample Output

4276
7141
4256
2126

HINT

Source

By 范浩强

中文题就不解释题意了……
做一道LCT主要是想在赛前复习一下LCT,然后再次感叹LCT的神奇……
这题很多同余方程,某个方程的解依赖于其他方程的解,由此可以构成一个类似于树的数据结构,所以比较自然的想到LCT。然后根据式子的关系,显然这些方程是可以相互合并的(把一个方程代入另一个方程),如此更适合用数据结构了。但是,问题来了,这里面可能出现环,该如何处理呢。我们注意到,父亲可以由儿子表示,爷爷可以由父亲表示,那么当出现环的时候,我完全可以通过合并,使得假想根和它的父亲fa(它的父亲也是它的后代)用同一个x表示。于是出现这种情况相当于x=k*x+b,相当于解这样的一个方程,这个就小菜一碟啦。所以说,我们可以选定一个假想根,然后断开它与它的父亲,但是要把它的父亲给记录下来,之后就是一颗完整的树。那么经过这样操作之后,就会形成一个森林。具体来说,我们可以看下面那个图来理解。
其中,虚线那条边表示被删掉的边,如此一堆关系可以形成一个森林。
然后,我们再考虑每一种操作。对于询问方程的结果,我们按照上面说的方法来求解。首先,对于要求的点x,它的解等于k[x]*根的解+b[x]。那么相当于要求根的解,而根的解=k[fa]*根的解+b[fa],这个fa就是我们之前删掉的那个父亲,在这时起作用。解这个方程就可以求出结果。
接着我们开修改操作。所谓修改主要就是考虑断开和重新连接嘛。这时,我们就要分情况讨论一下了,我们设修改的点为x,与之有关的方程是f。
如果x根而且f的根不是x,那么其他不管,直接把它的父亲变为f即可;
如果f的根也是x,这意味这什么呢?意味着构成了一个新的环,所以我们从这断开,并把这个父亲保存下来;
如果x不是根,那么显然关联方程改变,对应的与父亲的连边肯定是要断开的,然后还要再讨论一下啦,如果x在环上(可以看上图,不是所有点都在环上),那么就会对原来整个环产生影响,原本的环断开变成了真正的链,意味着虚拟断开的边不需要再断开了,把根的父亲变为原本断开的父亲即可;如果x不在环上,那么仅仅断开就行了,其他不影响;
这便是两种操作。然后关于LCT本身,还有要说的。因为我们保存的元素是方程的两个系数k和b,所以我们在定义的时候定义一个结构重载加法。然后很明显可以发现,这个重载的加法并不满足交换律,所以我们在合并的时候要格外小心,注意顺序。还有,就是LCT的beroot操作不要随便乱用,至少在这题是这样的。具体见代码:
#include<bits/stdc++.h>
#define mod 10007
#define N 30010
using namespace std;struct line
{int k,b;friend line operator + (const line a,const line b)                //重载加法{return line{a.k*b.k%mod,(b.b+b.k*a.b)%mod};}
};int n,m,t,inv[N],rt[N],v[N];struct Link_Cut_Tree
{int son[N][2],fa[N];line num[N],sum[N];inline bool which(int x){return son[fa[x]][1]==x;}bool isroot(int x){return !fa[x]||son[fa[x]][which(x)]!=x;}inline void push_up(int x){if (!x) return; sum[x]=num[x];if (son[x][0]) sum[x]=sum[son[x][0]]+sum[x];                //注意合并顺序,不能错if (son[x][1]) sum[x]=sum[x]+sum[son[x][1]];}inline void Rotate(int x){int y=fa[x]; bool ch=which(x);son[y][ch]=son[x][ch^1];son[x][ch^1]=y;if (!isroot(y)) son[fa[y]][which(y)]=x;fa[x]=fa[y]; fa[y]=x; fa[son[y][ch]]=y;push_up(y); push_up(x);}inline void splay(int x){while (!isroot(x)){int y=fa[x];if (!isroot(y)){if (which(x)^which(y)) Rotate(x);else Rotate(y);}Rotate(x);}}inline void access(int x){int y=0;while (x){splay(x);son[x][1]=y;push_up(x);y=x; x=fa[x];}}inline int getroot(int x){access(x); splay(x);while (son[x][0]) x=son[x][0];splay(x); return x;}inline void cut(int x){access(x); splay(x);son[x][0]=fa[son[x][0]]=0;push_up(x);}inline bool judge(int x,int y)                      //判定x,是否在y为根的环的环上{access(rt[y]); splay(rt[y]); splay(x);                 //如果在环上,那么在access(rt[y])之后再splay(x)return x==rt[y]||!isroot(rt[y]);                    //rt[y]一定不是根,或者x本身就是rt[y]}
} LCT;void init()
{inv[1]=1;for(int i=2;i<N;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod;                    //线性求逆元,解方程要用memset(rt,0,sizeof(rt));
}void dfs(int x)
{if (v[x]) return; v[x]=t;if (v[LCT.fa[x]]==t){rt[x]=LCT.fa[x];LCT.fa[x]=0;} else dfs(LCT.fa[x]);
}int main()
{init();scanf("%d",&n);for(int i=1;i<=n;i++){int k,f,b;scanf("%d%d%d",&k,&f,&b);LCT.fa[i]=f;LCT.num[i]=line{k,b};}for(int i=1;i<=n;i++)if (!v[i]) t++,dfs(i);scanf("%d",&m);while(m--){char op[5];int x,k,f,b,Rt;scanf("%s",op);if (op[0]=='A'){scanf("%d",&x);LCT.access(x); LCT.splay(x);line a=LCT.sum[x]; Rt=LCT.getroot(x);LCT.access(rt[Rt]); LCT.splay(rt[Rt]);line b=LCT.sum[rt[Rt]];if (b.k==1&&a.k!=0)                          //判定多组解和无解{if (b.b) puts("-1");else puts("-2");} else{int ans=b.b*inv[(1-b.k+mod)%mod]%mod;               //求根的解printf("%d\n",(a.k*ans+a.b)%mod);              //求x的解}} else{scanf("%d%d%d%d",&x,&k,&f,&b);LCT.access(x); LCT.splay(x);LCT.num[x]=line{k,b}; LCT.push_up(x);Rt=LCT.getroot(x);if (Rt!=x)                              //x不为根{LCT.cut(x);if (LCT.judge(x,Rt))                      //判定x是否在环上{LCT.access(Rt); LCT.splay(Rt);LCT.fa[Rt]=rt[Rt]; rt[Rt]=0;             //在的话把rt变为真正意义上的fa}}if (LCT.getroot(f)==x) rt[x]=f;                  //如果f的根与x相同,那么相当于构成了一个新的环else LCT.fa[x]=f;}}return 0;
}

BZOJ 2759 一个动态树好题(Link-Cut Tree+数学)相关推荐

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

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

  2. BZOJ2759 一个动态树好题

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

  3. 【bzoj2759】一个动态树好题

    Portal -->bzoj2759 Solution 哇我感觉这题真的qwq是很好的一题呀qwq 很神qwq反正我真的是自己想怎么想都想不到就是了qwq 首先先考虑一下简化版的问题应该怎么解决 ...

  4. link cut tree 入门

    鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构. link cut tree:研究popoqqq那个神ppt. bzoj1036:维护access操作就可以了. ...

  5. Link Cut Tree 学习笔记

    Link Cut Tree 学习笔记 说在前边 最近补 CF 碰见一道 LCT ,就打算学习一下这个东西...顺便复习一下 splay. 具体算法及实现 参考了FlashHu, Candy? P369 ...

  6. Link/Cut Tree学习笔记

    最近正是实验课的高峰期,我数了一下,除了毛概没有实验课,其他的课都有实验课...不过好在这些实验都不是很难.我尽力挤出时间用来刷题. 简介 Link/Cut Tree和树链剖分很相似,二者处理的问题也 ...

  7. Link Cut Tree详解

    Link Cut Tree ==Warning:千万不要跳读== 参考博客:https://www.cnblogs.com/flashhu/p/8324551.html 什么是动态树? 动态树问题, ...

  8. 模板:Link Cut Tree(LCT)

    文章目录 前言 解析 原理 rotate(x) splay(x) access(x) findroot(x) makeroot(x) split(x,y) link(x,y) cut(x,y) pus ...

  9. 15行代码AC——Link/Cut Tree CodeForces - 614A(爆long long处理+快速幂讲解)

    励志用少的代码做高效表达 Problem describe Programmer Rostislav got seriously interested in the Link/Cut Tree dat ...

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

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

最新文章

  1. 牛客题霸 [ 最长回文子串] C++题解/答案
  2. CIF、QCIF、HD1、D1格式介绍
  3. 易语言不用uac权限写到c盘,易语言制作UAC管理员模式添加器
  4. 如何查看Windows7系统版本
  5. mysql图片保存和读取
  6. 3.自编码器(变分自编码器,VAE)
  7. 文本文档打开来是写字板怎么办
  8. 总线体现在硬件上就是计算机主板,计算机考试练习题
  9. ubuntu16.04基于eclipse搭建px4编译环境+Jlink调式
  10. 2022-12-30:某天小美进入了一个迷宫探险,根据地图所示,这个迷宫里有无数个房间 序号分别为1、2、3、...入口房间的序号为1 任意序号为正整数x的房间,都与序号 2*x 和 2*x + 1
  11. 灵活部署的数据中心Pod已初见端倪
  12. python axes3d函数_Python绘制3D图形:Axes3D
  13. 【云享·人物】华为云AI高级专家白小龙:AI如何释放应用生产力,向AI工程化前行?
  14. 基于51单片机的智能化交通灯控制系统防止堵车疏散系统方案原理图程序设计
  15. 应届毕业生程序员的工资水平怎么样?聊聊程序员是不是高薪职业
  16. JAVA历险记--java基础知识--随堂笔记
  17. 象棋小巫师java下载_象棋小巫师美化加强版
  18. IPV6地址解析和邻居状态
  19. 注意的分类和规律以及生理机制
  20. 【mysql】只使用数据库DB如何实现--预定系统(古法)电影院座位预定

热门文章

  1. 发票OCR识别验真接口简介
  2. 2021-01-26
  3. Matlab画一半实线一半虚线,PPT中怎么绘制一个一半实线一半虚线的圆?
  4. Intel 80286微处理器功能结构
  5. 阿拉伯数字 - 书法 - 详解
  6. WIN10出现找不到WIFI解决办法
  7. 山石网科Hillstone防火墙L2TP详细配置步骤(官方最新版)
  8. c语言英文字母降序排列,英文单词排序
  9. c语言 牛逼代码,装逼技巧:程序员如何用代码证明自己牛逼!
  10. 【基于机器学习/深度学习的睡眠信号分类】主题必读论文推荐