【BZOJ2759】一道动态树的好题
来源:互联网 发布:软件研发过程模型 编辑:程序博客网 时间:2024/05/16 14:56
2759: 一个动态树好题
Time Limit: 10 Sec Memory Limit: 128 MB
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
确实是道动态树的好题啊= =
以下p=10007。
如果我们把每个i看作是一个点,p(i)看作是i的父亲,显然整个方程组会形成一个基环森林,而每个连通块都是一棵基环外向树,根据经验,我们可以拆掉环上的某条边,因此我们便得到了一个森林,便转化为了动态树的问题(ZGY神犇说可以用仙人掌来做,可是我不会= =)。
首先考虑如何回答询问。显然手动拆掉的那条边的起点是整棵树的根,我们可以对根记一个special father(以下简记为s)表示拆掉那条边的终点,我们设s的值为x,那么对于每个点我们都可得出它的值与x的线性关系。我们找到s后,实际上我们得到了s与它自己的线性关系,即我们得到了一个形如
修改的话,对于k和b的话access+splay直接改就可以了;修改父亲的时候要分多种情况讨论:如果这个点就是根,那么直接修改它的special father;反之,如果这个点原本在环上,此时我们需要把那条去掉的边补上。当它与它的父亲的边切掉后,它暂时成为了根,与新的父亲连接的时候,如果他们在一棵树上,便形成了一个环,赋值special father即可,否则直接连接。
#include<iostream>#include<cstdio>#define maxn 30000using namespace std;const int p=10007;struct data{ int k,b; data(){k=1,b=0;} data(int k,int b):k(k),b(b){} int cal(int x){return (k*x+b)%p;}};data operator+(data a,data b){ data ret; ret.k=a.k*b.k%p; ret.b=(a.b*b.k%p+b.b)%p; return ret;}void exgcd(int a,int b,int &x,int &y){ if(!b)x=1,y=0; else{ exgcd(b,a%b,y,x); y-=a/b*x; }}struct linkcuttree{ int ch[maxn+10][2],fa[maxn+10],sfa[maxn+10]; data val[maxn+10],sum[maxn+10]; int rc(int fa,int o){return ch[fa][1]==o;} int top(int o){return ch[fa[o]][0]!=o&&ch[fa[o]][1]!=o;} void pushup(int o){sum[o]=sum[ch[o][0]]+val[o]+sum[ch[o][1]];} int vis[maxn+10],ins[maxn+10]; void dfs(int u){ ins[u]=vis[u]=1; int v=fa[u]; if(ins[v]){ fa[u]=0; sfa[u]=v; } if(!vis[v])dfs(v); ins[u]=0; } void init(int n){ for(int i=1;i<=n;i++){ int k,b; scanf("%d%d%d",&k,&fa[i],&b); val[i]=sum[i]=data(k,b); } for(int i=1;i<=n;i++)if(!vis[i])dfs(i); } void rot(int o){ int f=fa[o],r=rc(f,o); if(!top(f))fa[ch[fa[f]][rc(fa[f],f)]=o]=fa[f]; else fa[o]=fa[f]; fa[ch[f][r]=ch[o][r^1]]=f; fa[ch[o][r^1]=f]=o; pushup(f); pushup(o); } void splay(int o){ while(!top(o)){ if(!top(fa[o])&&rc(fa[fa[o]],fa[o])==rc(fa[o],o))rot(fa[o]); rot(o); } } void access(int u){ int v=0; while(u){ splay(u); ch[u][1]=v; pushup(u); v=u; u=fa[u]; } } int findroot(int u){ access(u); splay(u); int ro=u; while(ch[ro][0])ro=ch[ro][0]; splay(ro); return ro; } int query(int u){ access(u); splay(u); data v1=sum[u]; int ro=findroot(u),f=sfa[ro]; access(f); splay(f); data v2=sum[f]; if(v2.k==1)return v2.b?-1:-2; if(v2.k==0)return v1.cal(v2.b); int x,y; exgcd(v2.k-1,p,x,y); return v1.cal((p-x)%p*v2.b%p); } void cut(int u){ access(u); splay(u); fa[ch[u][0]]=0; ch[u][0]=0; pushup(u); } void join(int u,int f){ access(u); splay(u); fa[u]=f; } int oncirclr(int u,int ro){ int f=sfa[ro]; if(u==f)return 1; access(f); splay(f); splay(u); return !top(f); } void update(int u,int f,int k,int b){ access(u); splay(u); val[u]=data(k,b); pushup(u); int ro=findroot(u); if(u==ro){ int rf=findroot(f); if(rf==ro)sfa[u]=f; else{ sfa[u]=0; join(u,f); } }else{ if(oncirclr(u,ro)){ cut(u); join(ro,sfa[ro]); sfa[ro]=0; int rf=findroot(f); if(rf==u)sfa[u]=f; else join(u,f); }else{ cut(u); int rf=findroot(f); if(rf==u)sfa[u]=f; else join(u,f); } } }}lct;int main(){ int n; scanf("%d",&n); lct.init(n); int q; scanf("%d",&q); char e[2]; int x,k,b,f; while(q--){ scanf("%s%d",e,&x); if(e[0]=='A')printf("%d\n",lct.query(x)); else{ scanf("%d%d%d",&k,&f,&b); lct.update(x,f,k,b); } } return 0;}
- 【BZOJ2759】一道动态树的好题
- 【HYSBZ 2759】一道动态树的好题
- BZOJ 2759 一道动态树的好题
- 【BZOJ2759】一个动态树好题
- [LCT] BZOJ2759.一个动态树好题
- bzoj2759
- 一道递归的好题
- 一道动态规划的题
- bzoj2759:一个动态树好题 (LCT+Exgcd)
- 一道超级好的笔试题
- 一道防AK的好题【数列】
- 一道好题
- dfs好题一道
- 一道搜索好题
- 一道搜索好题
- 一道简单的动态规划题
- 2012年北约自主招生的一道数学好题
- 树形DP POJ3659 好难的一道题
- 103. Binary Tree Zigzag Level Order Traversal
- 258. Add Digits LeetCode
- Hibernate配置文件详解
- Codeforces 618 E . Robot Arm
- 104. Maximum Depth of Binary Tree LeetCode
- 【BZOJ2759】一道动态树的好题
- Maven 项目无法在Ecplise加进tomcat server
- 使用RandomAccessFile API
- 顺序表应用1:多余元素删除之移位算法
- Android中AIDL详解
- 237. Delete Node in a Linked List LeetCode
- 226. Invert Binary Tree LeetCode
- Xcode 【ActivatePowerMode & XActivatePowerMode】
- MMU(Memory Management Units) Chapter-14