滚回来学文化课了……

题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=2759

题解

LCT,显然的做法是维护链上所有一次函数的复合。
如何处理根的问题?

考虑所有的连通块都建成有根树,另外记录每个根的父亲。
修改父亲的时候,如果修改的是根,那么要么直接改,要么合并两个连通块,根变为非根;如果修改的不是根,要特判分裂了两个连通块导致根的父亲进了新的连通块的情况,如果如此则需重新合并,根变为非根,其余直接改即可。

时间复杂度\(O(n\log n)\).

代码

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cassert>
using namespace std;void read(int &x)
{int f=1;x=0;char s=getchar();while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}x*=f;
}const int N = 3e4;
const int P = 1e4+7;
int inv[P+2];
struct Data
{int a,b;Data() {}Data(int _a,int _b) {a = _a,b = _b;}Data operator *(const Data &arg) const {return Data(a*arg.a%P,(b*arg.a+arg.b)%P);}int calc(int x) {return (a*x+b)%P;}int solve(){if(a==0) {return b==0?-2:-1;}return inv[a]*(P-b)%P;}
};
int fa[N+3];
int uf[N+3];
int n,q;int findfa(int u)
{int i = u;while(u!=uf[u]) {u = uf[u];}while(u!=uf[i]){int j = uf[i]; uf[i] = u; i = j;}return u;
}struct SplayNode
{int son[2],fa; Data val,sum;
} spl[N+3];
bool isroot(int u) {return spl[spl[u].fa].son[0]!=u && spl[spl[u].fa].son[1]!=u;}
void pushup(int u)
{int ls = spl[u].son[0],rs = spl[u].son[1];spl[u].sum = spl[u].val;if(ls) {spl[u].sum = spl[ls].sum*spl[u].sum;}if(rs) {spl[u].sum = spl[u].sum*spl[rs].sum;}
}
void rotate(int u)
{int x = spl[u].fa,y = spl[x].fa,dir = u==spl[x].son[0];if(!isroot(x)) {spl[y].son[x==spl[y].son[1]] = u;}spl[u].fa = y;spl[x].son[dir^1] = spl[u].son[dir];if(spl[u].son[dir]) {spl[spl[u].son[dir]].fa = x;}spl[u].son[dir] = x; spl[x].fa = u;pushup(x);
}
void splaynode(int u)
{int x = u;while(!isroot(x)){x = spl[x].fa;}while(!isroot(u)){int y = spl[u].fa,z = spl[y].fa;if(!isroot(y)) {(u==spl[y].son[1])^(y==spl[z].son[1]) ? rotate(u) : rotate(y);}rotate(u);}pushup(u);
}
void access(int u)
{for(int i=0; u; i=u,u=spl[u].fa){splaynode(u);spl[u].son[1] = i;pushup(u);}
}
int findroot(int u,int flg=0)
{access(u); splaynode(u);while(spl[u].son[0]) u = spl[u].son[0];if(flg) splaynode(u);return u;
}
void link(int u,int v) //fa[u]=v
{
//  printf("link %d %d\n",u,v);access(u); splaynode(u);spl[u].fa = v;
}
void cut(int u) //fa[u]=v
{
//  printf("cut %d\n",u);access(u); splaynode(u);int v = spl[u].son[0]; spl[u].son[0] = spl[v].fa = 0;pushup(u);
}
void modify(int u,Data x)
{splaynode(u);spl[u].val = x;
}int main()
{inv[1] = 1; for(int i=2; i<P; i++) inv[i] = P-(P/i*inv[P%i]%P);scanf("%d",&n);for(int i=1; i<=n; i++) uf[i] = i;for(int i=1; i<=n; i++){int u,x,y; scanf("%d%d%d",&x,&u,&y);spl[i].val = spl[i].sum = Data(x,y);int uu = findfa(u);if(uu==i){fa[i] = u;}else{link(i,u);uf[findfa(i)] = uu;}}scanf("%d",&q);while(q--){char opt[5]; scanf("%s",opt+1);if(opt[1]=='A'){int u; scanf("%d",&u);int rt = findroot(u);access(fa[rt]); splaynode(fa[rt]);int x = Data((spl[fa[rt]].sum.a-1+P)%P,spl[fa[rt]].sum.b).solve();if(x<0) {printf("%d\n",x);}else{access(u); splaynode(u);int ans = spl[u].sum.calc(x);printf("%d\n",ans);}}else if(opt[1]=='C'){int u,ax,ay,v; scanf("%d%d%d%d",&u,&ax,&v,&ay);modify(u,Data(ax,ay));if(fa[u]){int rtv = findroot(v);if(rtv==u) {fa[u] = v;}else{fa[u] = 0;link(u,v);}}else{int rt = findroot(u);cut(u);int rtf = findroot(fa[rt]);if(rtf==u){link(rt,fa[rt]);fa[rt] = 0;}int rtv = findroot(v);if(rtv==u) {fa[u] = v;}else {link(u,v);}}}}return 0;
} 

BZOJ 2759 一个动态树好题 (LCT)相关推荐

  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. 【bzoj2759】一个动态树好题

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

  3. BZOJ 3730: 震波 动态树分治 线段树 lca

    3730: 震波 Time Limit: 15 Sec  Memory Limit: 256 MB Submit: 1202  Solved: 288 [Submit][Status][Discuss ...

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

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

  5. SPOJ OTOCI 动态树 LCT

    SPOJ OTOCI 裸的动态树问题. 回顾一下我们对树的认识. 最初,它是一个连通的无向的无环的图,然后我们发现由一个根出发进行BFS 会出现层次分明的树状图形. 然后根据树的递归和层次性质,我们得 ...

  6. 动态树(LCT)初探

    文章目录 前置技能 那么直接开始吧 原树与辅助树 Access操作 含义 Addition: Splay 旋转操作 Splay操作 辅助树上的Access MakeRoot操作 Link操作 Cut操 ...

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

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

  8. bzoj 3730: 震波 动态点分治+树链剖分+线段树

    ##### 题目描述 : 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]. 不幸的是,这片土地常常发生地震,并且随 ...

  9. Luogu P1198 BZOJ 1012 最大数 (线段树)

    Luogu P1198 BZOJ 1012 最大数 (线段树) 手动博客搬家: 本文发表于20170821 14:32:05, 原地址https://blog.csdn.net/suncongbo/a ...

最新文章

  1. 217. Contains Duplicate - LeetCode
  2. 华为第四代服务器芯片Hi1620,华为第四代自研芯片Hi1620曝光, 全球首款7nm的ARM处理器...
  3. 怎么在uefi解锁磁盘_系统重装时,如何秒判Windows启动是UEFI/Legacy?3步就够了!...
  4. java怎么输出9 99的形式_java如何输出99乘法表
  5. leetcode543. 二叉树的直径
  6. Visual Studio下的 JS CSS 压缩和编辑插件
  7. MySQL 5.7.25 在Windows 7中安装的记录
  8. 操作系统原理(五)存储管理
  9. python读取pdf内容转word_卧槽!Pdf转Word用Python轻松搞定!
  10. DataRow[] /数组转换datatable!
  11. Rhino(Grasshopper)+PaddleX快速建模
  12. vMix(视频混合器软件)v22.0.0.48免费版
  13. 金士顿DT100G3(16G) U盘修复
  14. JavaScript零基础入门 11:JavaScript实现图片上传并预览
  15. 抖音最近很火的游戏直播:挤地铁教程+源码+软件下载
  16. 打破国外垄断 数字音频国家标准DRA颁布
  17. 使用火焰图(FlameGraph)分析程序性能
  18. 技术的真相 | 从AR口红试妆了解人工智能试妆技术
  19. NEON优化:软件性能优化、降功耗怎么搞?
  20. 深度学习-Word Embedding的详细理解(包含one-hot编码和cos余弦相似度)

热门文章

  1. 吴恩达《构建机器学习项目》精炼笔记(1)-- 机器学习策略(上)
  2. VS中添加命令行参数的方法
  3. Qt修炼手册11_多线程编程和QThread类
  4. c#中调用Excel
  5. Ie6下asp.net 中treeview自动随鼠标变小的修复
  6. JS 枚举型变量操作
  7. 二进制转换为八进制-栈方式实现
  8. Linux 0.00 的编译和运行
  9. 进入保护模式(一)——《x86汇编语言:从实模式到保护模式》读书笔记12
  10. 【不会吧不会吧,不会有人真的三分钟入门Python了吧?】Python编程基础