BZOJ2759 一个动态树好题 LCT
题解:
的确是动态树好题
首先由于每个点只有一个出边
这个图构成了基环内向树
我们观察那个同余方程组
一旦形成环的话我们就能知道环上点以及能连向环上点的值是多少了
所以我们只需要用一种结构来维护两个不是直接相连点的状态
由于有删边连边操作,比较容易想到lct
我们按照套路将它拆掉一条边形成一颗树
因为我们现在只知道环上某一点的值,所以我们这棵树应该是不随便换根的
每次询问只需要把当前这个点access再splay一下 查询用根怎么表示就可以了
修改方程组等价于删一条边,连一条边
删的边如果不在环上 直接删
- #include <bits/stdc++.h>
- using namespace std;
- #define rint register int
- #define IL inline
- #define rep(i,h,t) for(int i=h;i<=t;i++)
- #define dep(i,t,h) for(int i=t;i>=h;i--)
- #define ll long long
- #define me(x) memset(x,0,sizeof(x))
- #define mep(x,y) memcpy(x,y,sizeof(y))
- #define mid ((h+t)>>1)
- namespace IO{
- char ss[<<],*A=ss,*B=ss;
- IL char gc()
- {
- return A==B&&(B=(A=ss)+fread(ss,,<<,stdin),A==B)?EOF:*A++;
- }
- template<class T> void read(T &x)
- {
- rint f=,c; while (c=gc(),c<||c>) if (c=='-') f=-; x=(c^);
- while (c=gc(),c>&&c<) x=(x<<)+(x<<)+(c^); x*=f;
- }
- template<class T>void read2(T &x)
- {
- rint c;
- while (c=gc(),c!='A'&&c!='C'); x=c;
- }
- char sr[<<],z[]; ll Z,C1=-;
- template<class T>void wer(T x)
- {
- if (x<) sr[++C1]='-',x=-x;
- while (z[++Z]=x%+,x/=);
- while (sr[++C1]=z[Z],--Z);
- }
- IL void wer1()
- {
- sr[++C1]=' ';
- }
- IL void wer2()
- {
- sr[++C1]='\n';
- }
- template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;}
- template<class T>IL void mina(T &x,T y) {if (x>y) x=y;}
- template<class T>IL T MAX(T x,T y){return x>y?x:y;}
- template<class T>IL T MIN(T x,T y){return x<y?x:y;}
- };
- const int N=5e4;
- int k[N],p[N],b[N];
- const int mo=;
- struct re{
- int a,b;
- re operator *(const re o) const
- {
- re c;
- c.a=a*o.a%mo; c.b=(o.a*b+o.b)%mo;
- return c;
- }
- };
- IL int fsp(int x,int y)
- {
- int now=;
- while (y)
- {
- if (y&) now=now*x%mo;
- x=x*x%mo; y>>=;
- }
- return now;
- }
- struct lct{
- int ls[N],fa[N],rs[N],sp[N],ans[N];
- re sum[N],v[N];
- IL void updata(int x)
- {
- if (ls[x]) sum[x]=sum[ls[x]]*v[x];
- else sum[x]=v[x];
- if (rs[x]) sum[x]=sum[x]*sum[rs[x]];
- }
- IL bool pd(int x)
- {
- return ls[fa[x]]==x||rs[fa[x]]==x;
- }
- void rotate(int x,int y)
- {
- int f1=fa[x];
- if (y==)
- {
- rs[f1]=ls[x];
- if (ls[x]) fa[ls[x]]=f1;
- } else
- {
- ls[f1]=rs[x];
- if (rs[x]) fa[rs[x]]=f1;
- }
- fa[x]=fa[f1];
- if (pd(f1))
- {
- if (ls[fa[f1]]==f1) ls[fa[f1]]=x;
- else rs[fa[f1]]=x;
- }
- if (y==) ls[x]=f1; else rs[x]=f1;
- fa[f1]=x;
- updata(f1); updata(x);
- }
- void splay(int x)
- {
- // dfs(x);
- int f1=fa[x];
- while (pd(x))
- {
- if (!pd(f1))
- {
- if (ls[f1]==x) rotate(x,); else rotate(x,);
- } else
- if (ls[fa[f1]]==f1)
- if (ls[f1]==x) rotate(f1,),rotate(x,);
- else rotate(x,),rotate(x,);
- else
- if (rs[f1]==x) rotate(f1,),rotate(x,);
- else rotate(x,),rotate(x,);
- f1=fa[x];
- }
- }
- void access(int x)
- {
- for (int y=;x;y=x,x=fa[x])
- {
- splay(x); rs[x]=y; updata(x);
- }
- }
- int fdr(int x)
- {
- access(x); splay(x);
- while (ls[x]) x=ls[x];
- return x;
- }
- int query(int x)
- {
- access(x); splay(x);
- int ro=fdr(x);
- re kk=sum[x];
- access(sp[ro]);
- splay(sp[ro]);
- int ans,a=sum[sp[ro]].a,b=sum[sp[ro]].b;
- if (a==)
- if (b==) ans=-; else ans=-;
- ans=(fsp((-a),mo-)*b%mo+mo)%mo;
- if (ans==-) return(-);
- if (ans==-) return(-);
- return ((ans*kk.a+kk.b)%mo+mo)%mo;
- }
- IL void cut(int x)
- {
- access(x); splay(x); ls[x]=fa[ls[x]]=; updata(x);
- }
- void change(int x,int k,int p,int b)
- {
- int rt=fdr(x);
- if (x==rt)
- {
- if (fdr(p)!=x)
- {
- sp[x]=; fa[x]=p;
- } else
- {
- sp[x]=p;
- }
- } else
- {
- access(sp[rt]); splay(sp[rt]);
- int z=x;
- while (pd(z)) z=fa[z];
- if (z==sp[rt])
- {
- cut(x);
- access(rt); splay(rt); fa[rt]=sp[rt]; sp[rt]=;
- } else
- {
- cut(x);
- }
- if (fdr(p)!=x)
- {
- fa[x]=p;
- } else
- {
- sp[x]=p;
- }
- }
- v[x]=(re){k,b}; splay(x);
- }
- IL void link(int x,int y)
- {
- if (fdr(x)!=fdr(y))
- {
- fa[x]=y;
- } else sp[x]=y;
- }
- }S;
- int main()
- {
- freopen("1.in","r",stdin);
- freopen("1.out","w",stdout);
- int n;
- IO::read(n);
- rep(i,,n)
- {
- IO::read(k[i]),IO::read(p[i]),IO::read(b[i]);
- S.v[i]=(re){k[i],b[i]};
- S.link(i,p[i]);
- }
- int q;
- IO::read(q);
- rep(i,,q)
- {
- char c;
- IO::read2(c);
- if (c=='A')
- {
- int a;
- IO::read(a);
- IO::wer(S.query(a)); IO::wer2();
- } else
- {
- int a,b,c,d;
- IO::read(a); IO::read(b); IO::read(c); IO::read(d);
- S.change(a,b,c,d);
- }
- }
- fwrite(IO::sr,,IO::C1+,stdout);
- return ;
- }
删的边如果在环上 并且没有连上 把标记清除
删的边如果在环上 并且连上了 把这条边段删了,然后把标记边连上
BZOJ2759 一个动态树好题 LCT的更多相关文章
- BZOJ2759一个动态树好题 LCT
题如其名啊 昨天晚上写了一发忘保存 只好今天又码一遍了 将题目中怕$p[i]$看做$i$的$father$ 可以发现每个联通块都是一个基环树 我们对每个基环删掉环上一条边 就可以得到一个森林了 可以用 ...
- BZOJ2759: 一个动态树好题
BZOJ2759: 一个动态树好题 Description 有N个未知数x[1..n]和N个等式组成的同余方程组:x[i]=k[i]*x[p[i]]+b[i] mod 10007其中,k[i],b[i ...
- BZOJ 2759 一个动态树好题 (LCT)
PoPoQQQ 再一次orz-没看得特别明白的可以回来看看蒟蒻的补充口胡 我这里提一下关于splaysplaysplay维护的子树信息- 在原树上考虑,对于每一个点iii都有这样一个信息xi=ki∗x ...
- [BZOJ 2759] 一个动态树好题
[BZOJ 2759] 一个动态树好题 题目描述 首先这是个基环树. 然后根节点一定会连出去一条非树边.通过一个环就可以解除根的答案,然后其他节点的答案就可以由根解出来. 因为要修改\(p_i\),所 ...
- bzoj 2759一个动态树好题
真的是动态树好题,如果把每个点的父亲设成p[x],那么建出来图应该是一个环套树森林,拆掉一条边,就变成了动态树,考虑维护什么,对于LCT上每个节点,维护两组k和b,一组是他到他父亲的,一组是他LCT子 ...
- 【bzoj2759】一个动态树好题
Portal -->bzoj2759 Solution 哇我感觉这题真的qwq是很好的一题呀qwq 很神qwq反正我真的是自己想怎么想都想不到就是了qwq 首先先考虑一下简化版的问题应该怎么解决 ...
- 【刷题】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) ...
- BZOJ 2759 一个动态树好题(动态树)
题意 https://www.lydsy.com/JudgeOnline/problem.php?id=2759 思路 每个节点仅有一条有向出边, 这便是一棵基环内向树,我们可以把它在 \(\text ...
- 动态树Link-cut tree(LCT)总结
动态树是个好玩的东西 LCT题集 预备知识 Splay 树链剖分(好像关系并不大) 动态树(Link-cut tree) 先搬dalao博客 什么是LCT? 动态树是一类要求维护森林的连通性的题的总称 ...
随机推荐
- Linux安装NodeJS
Linux中安装nodejs 去官网下载和自己系统匹配的文件: 英文网址:https://nodejs.org/en/download/ 中文网址:http://nodejs.cn/download/ ...
- (BST 递归) leetcode98. Validate Binary Search Tree
Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as ...
- ansible迭代/迭代嵌套/同步异步/特殊topic说明
tasks直接举例说明: ---- host: docker remote_user: root gather_facts: yes serial: 3 #表示同一时间控制主机数量(值可以是数值 ...
- python3 练手实例8 批量命名图片
#coding:utf-8 import os import tkinter as tk from tkinter import filedialog root = tk.Tk() root.with ...
- python flsak 框架
1.flask 轻量级微型web框架 优点:微框架.简单.可扩展 将flask变量实例化到app变量中 如果想要flask自动加载修改后的代码,要app.run(debug=True) 2.路由和视 ...
- linux内核开发入门学习
1. 目录结构 内核源代码下载 https://www.kernel.org arch目录 arch是architecture的缩写. 内核所支持的每种CPU体系,在该目录下都有对应的子目录.每个CP ...
- python3 正则表达式学习笔记
re.match函数 re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none. ~匹配成功re.match方法返回一个匹配的对象,否则返回No ...
- 使用scrapy爬虫,爬取起点小说网的案例
爬取的页面为https://book.qidian.com/info/1010734492#Catalog 爬取的小说为凡人修仙之仙界篇,这边小说很不错. 正文的章节如下图所示 其中下面的章节为加密部 ...
- Lua教程
Lua中的类型与值 Lua中的表达式 Lua中的语句 Lua中的函数 Lua中的闭包 Lua 中 pairs 和 ipairs 的区别 Lua中的迭代器与泛型for Lua中的协同程序 Lua中__i ...
- es6 总结知识点
1. let 和 const 只在代码块中有效 {} js块级作用域. const 定义的对象是可以改变其属性的 const a =[], b={} ; a.push(1); b.a=1; / ...