BZOJ2759: 一个动态树好题

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

题解Here!
额,这的确是道$LCT$的好题。。。
好到毒瘤了。。。
题目大意:
给定$n$个形如$x_i=k_i\times x_{p_i}+b_i\mod 10007$的同余方程组,支持修改和询问。
出题人脑洞真大。。。

将每个点$i$的父亲设为$p_i$,我们将会得到一座基环树林。

将环上的一条边拆掉,在边的起始节点新开个域$special_father$记录这条边。($P.S$:好浪费,但是没办法)

于是我们得到了一座森林,显然可以用LCT来维护。

每个节点的权值是个二元组$(k,b)$,记录每个点关于答案的线性关系,合并时左侧代入右侧中。

查询时将$root$的$special\ father$进行$Access+Splay$操作,然后借助这个环通过$exgcd$求出$root.special\ father$的值,然后$Access(x)+Splay(x)$代入出解。

单点查询,没有换根等操作,翻转标记都没有,舒服!

但是那个无解和无穷解怎么整?

我们特判一波:

若环上$k==1$,讨论$b$:

若$b==0$则无穷多解;否则无解

注意$k==0$时要加一些处理,正常求$exgcd$求不出来。

修改的话,因为是单点修改,所以最开始要$Access+Splay$。

修改$x$的父节点时需要讨论:

首先切掉原先的父节点,这个不必多说。

如果$x$是所在树的根 直接切掉$special\ father$就好。

如果$x$不是根,切掉$x$与父节点的联系,然后讨论$x$是否在环上。

设$x$所在树的根节点为$root$。

若$root.special\ father$所在树的根不为$root$,则$x$在环上,将$root$的$special\ father$变为$root$的$fa$节点。

否则切断父节点完毕。

然后讨论新的父节点$p$是否在$x$的子树中

若在,将$x$的$special\ father$设为$p$。

若不在,将$x$的$fa$设为$p$。

然后就是一大堆乱七八糟的细节问题,这个只能看代码了。。。

记得一开始的空节点有值!

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 40010
#define MOD 10007
using namespace std;
int n,m,T=1;
int fa[MAXN],vis[MAXN];
struct node{
int k,b;
node operator +(const node p)const{
node x;
x.k=k*p.k%MOD;
x.b=(b*p.k+p.b)%MOD;
return x;
}
inline int f(int x){return (x*k+b)%MOD;}
};
struct Link_Cut_Tree{
int son[2];
int f,sf;//fa,special_father
node v,sum;
}a[MAXN];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
inline bool isroot(int rt){
return a[a[rt].f].son[0]!=rt&&a[a[rt].f].son[1]!=rt;
}
inline void pushup(int rt){
a[rt].sum=a[a[rt].son[0]].sum+a[rt].v+a[a[rt].son[1]].sum;
}
inline void newnode(int rt,int k,int b){
a[rt].son[0]=a[rt].son[1]=a[rt].f=a[rt].sf=0;
a[rt].v.k=a[rt].sum.k=k;
a[rt].v.b=a[rt].sum.b=b;
}
inline void turn(int rt){
int x=a[rt].f,y=a[x].f,k=a[x].son[0]==rt?1:0;
if(!isroot(x)){
if(a[y].son[0]==x)a[y].son[0]=rt;
else a[y].son[1]=rt;
}
a[rt].f=y;a[x].f=rt;a[a[rt].son[k]].f=x;
a[x].son[k^1]=a[rt].son[k];a[rt].son[k]=x;
pushup(x);pushup(rt);
}
void splay(int rt){
while(!isroot(rt)){
int x=a[rt].f,y=a[x].f;
if(!isroot(x)){
if((a[y].son[0]==x)^(a[x].son[0]==rt))turn(rt);
else turn(x);
}
turn(rt);
}
}
void access(int rt){
for(int i=0;rt;i=rt,rt=a[rt].f){
splay(rt);
a[rt].son[1]=i;
pushup(rt);
}
}
int findroot(int rt){
access(rt);splay(rt);
while(a[rt].son[0])rt=a[rt].son[0];
return rt;
}
int exgcd(int a,int b,int &x,int &y){
if(!b){
x=1;y=0;
return a;
}
int s=exgcd(b,a%b,y,x);
y-=a/b*x;
return s;
}
int inverse(int k){
int x=0,y=0;
int t=exgcd((k+MOD)%MOD,MOD,x,y);
return (x%MOD+MOD)%MOD;
}
void dfs(int rt){
vis[rt]=T;
if(vis[fa[rt]]==T){
a[rt].sf=fa[rt];
return;
}
a[rt].f=fa[rt];
if(!vis[fa[rt]])dfs(fa[rt]);
}
void update(int x,int k,int p,int b){
int rt=findroot(x);
a[x].v.k=k;a[x].v.b=b;
pushup(x);
if(x==rt){
a[x].sf=0;
}
else{
access(x);splay(x);
a[a[x].son[0]].f=0;a[x].son[0]=0;
pushup(x);
if(findroot(a[rt].sf)!=rt){
access(rt);splay(rt);
a[rt].f=a[rt].sf;
a[rt].sf=0;
}
}
access(x);splay(x);
if(findroot(p)==x)a[x].sf=p;
else a[x].f=p;
}
void query(int x){
int rt=findroot(x);
access(a[rt].sf);splay(a[rt].sf);
int k=a[a[rt].sf].sum.k,b=a[a[rt].sf].sum.b;
if(k==1){
if(b==0)printf("-2\n");
else printf("-1\n");
return;
}
int t=(MOD-b)*inverse(k-1)%MOD;
access(x);splay(x);
printf("%d\n",a[x].sum.f(t));
}
void work(){
char ch[2];
int x,k,p,b;
while(m--){
scanf("%s",ch);x=read();
if(ch[0]=='A'){
query(x);
}
else{
k=read();p=read();b=read();
update(x,k,p,b);
}
}
}
void init(){
int k,p,b;
n=read();
newnode(0,1,0);//空节点有值!
for(int i=1;i<=n;i++){
k=read();p=read();b=read();
fa[i]=p;
newnode(i,k,b);
}
m=read();
for(int i=1;i<=n;i++)if(!vis[i]){dfs(i);T++;}
}
int main(){
init();
work();
return 0;
}

BZOJ2759: 一个动态树好题的更多相关文章

  1. BZOJ2759 一个动态树好题 LCT

    题解: 的确是动态树好题 首先由于每个点只有一个出边 这个图构成了基环内向树 我们观察那个同余方程组 一旦形成环的话我们就能知道环上点以及能连向环上点的值是多少了 所以我们只需要用一种结构来维护两个不 ...

  2. BZOJ2759一个动态树好题 LCT

    题如其名啊 昨天晚上写了一发忘保存 只好今天又码一遍了 将题目中怕$p[i]$看做$i$的$father$ 可以发现每个联通块都是一个基环树 我们对每个基环删掉环上一条边 就可以得到一个森林了 可以用 ...

  3. [BZOJ 2759] 一个动态树好题

    [BZOJ 2759] 一个动态树好题 题目描述 首先这是个基环树. 然后根节点一定会连出去一条非树边.通过一个环就可以解除根的答案,然后其他节点的答案就可以由根解出来. 因为要修改\(p_i\),所 ...

  4. bzoj 2759一个动态树好题

    真的是动态树好题,如果把每个点的父亲设成p[x],那么建出来图应该是一个环套树森林,拆掉一条边,就变成了动态树,考虑维护什么,对于LCT上每个节点,维护两组k和b,一组是他到他父亲的,一组是他LCT子 ...

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

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

  6. 【刷题】BZOJ 2759 一个动态树好题

    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) ...

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

    题意 https://www.lydsy.com/JudgeOnline/problem.php?id=2759 思路 每个节点仅有一条有向出边, 这便是一棵基环内向树,我们可以把它在 \(\text ...

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

    PoPoQQQ 再一次orz-没看得特别明白的可以回来看看蒟蒻的补充口胡 我这里提一下关于splaysplaysplay维护的子树信息- 在原树上考虑,对于每一个点iii都有这样一个信息xi=ki∗x ...

  9. bzoj2049-洞穴勘测(动态树lct模板题)

    Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好 ...

随机推荐

  1. 记一次安装centos7及gnome桌面

    https://blog.csdn.net/bingbingtea/article/details/79553669

  2. 一维数组解最长上升公共子序列(LCIS)

    #include<bits/stdc++.h> using namespace std; + ; int n,a[maxn],b[maxn],dp[maxn]; int main() { ...

  3. qt使用

    1安装qt软件(.run文件) . chmod 777 qt.....run ./qt...run或sudo ./qt...run(安装目录不一样) 2.sudo gedit .bashrc添加以下内 ...

  4. 【TJOI2017】可乐

    题目描述 加里敦星球的人们特别喜欢喝可乐.因而,他们的敌对星球研发出了一个可乐机器人,并且放在了加里敦星球的\(1\)号城市上.这个可乐机器人有三种行为:停在原地,去下一个相邻的城市,自爆.它每一秒都 ...

  5. java反射原理运用

    1.首先用Java反射机制的要做到的一个目的:我们都知道通过得到一个对象中的指定方法或者属性等,基于这个原理我们来做一个 通用的功能,让客户端可以通过传入的对象和一个标识去调用这个对象里自己想要的方法 ...

  6. C# 将 WebService 封装成动态库

    C# 将 WebService 封装成动态库 服务与服务之间的远程调用,经常会通过Web Service来实现,Web Service是支持跨语言调用的,可以是java调用c++或c#调用java等, ...

  7. RabbitMQ 最常用的三大模式

    目录 Direct 模式 Topic 模式 Fanout 模式 Direct 模式 所有发送到 Direct Exchange 的消息被转发到 RouteKey 中指定的 Queue. Direct ...

  8. 邁向IT專家成功之路的三十則鐵律 鐵律二十:IT人證照之道-收斂

    這是一個各行各業都講究專業證照的世代,彷彿證照只要比別人少一些就感覺自己遜掉了.現今IT領域的證照肯定是所有行業中最複雜的,無論是想求職升遷的還是想轉進IT跑道的,許多人由於受到媒體與廣告的影響,都不 ...

  9. 快讯 | FireEye在GitHub上开源密码破解工具GoCrack

    近日,FireEye 开源了一款密码破解工具 GoCrack,可在多机器上部署破解任务. GoCrack 是由 FireEye’s Innovation and Custom Engineering ...

  10. 在Intellij上面导入项目 & AOP示例项目 & AspectJ学习 & Spring AoP学习

    为了学习这篇文章里面下载的代码:http://www.cnblogs.com/charlesblc/p/6083687.html 需要用Intellij导入一个已有工程.源文件原始内容也可见:link ...