BZOJ2759: 一个动态树好题

n<=30000个同余方程:$x_i\equiv k_i*x_{p_i}+b_i (mod 10007)$。m<=100000个操作:一、修改某个不等式的$k_i,p_i,b_i$,二、查询某个变量的值。无解-1,无穷解-2.

极其好玩的一道题。不像某些“绝世好题”实际是水题。。

首先按依赖关系可以建成基环树啦,因为n个点,每个点1条出边嘛。

错误!是基环森林。因为忽略了这个,所以本地找别人代码对拍时造数据也是造成一棵基环树,查了将近5h才发现这回事。。

很好。

要求解的话,肯定先从那个环入手,环上算出某个点的值,然后一路推下去即可。可以先列个简单点的东西:如果有同余方程组

$x_1\equiv k_1*x_{2}+b_1$

$x_2\equiv k_2*x_{3}+b_2$
......
$x_n\equiv k_n*x_{1}+b_n$

乱搞+不完全归纳+YY+找规律可得:$x_1=\prod_{i=1}^{n}k_i x_1+\sum_{i=1}^{n}b_i\prod_{j=1}^{i-1}k_j$。这两坨系数可以用可合并的数据结构维护。

那写到这里自然会选择LCT啦(因为题目说的)。

首先基环树的常见套路:不换根,然后在根节点(有向图,这个所谓的根节点一定在环上)那里存一个东西记基环树比普通树多出来的那条边。我把他叫做$biu$,因为他就是突然出现的,就有一种$biu$的感觉,是不是很生动啊!那相应的$cut$和$link$函数也要改改,如果要把$x$和其父$y$砍掉,如果$y$是$x$的$biu$,那就$x$的$biu$清零,否则照正常操作$cut$。$link$同理,但记得如果照正常套路$link$的话$x$的$biu$要清零,下面会说。

来看修改操作。由于要变信息所以把他$access+splay$后直接换信息再$up$最方便。然后来改爸爸,首先和原爸爸$cut$掉,然后和新爸爸$link$上。等会,这里原来有条$biu$边的,操作完之后可能$biu$边不$biu$了,也就是可能环上除了$biu$的一条边被$cut$了,那就$link$一下他(被修改点)所在的树的根节点以及根节点的$biu$,如果真的发生了这种情况,在$link$那里直接$biu$清零并将之连上。

然后询问。先找到真正的根节点(不是辅助splay树上的)$root$的$biu$,$access(biu)$,然后把那系数整理出来带进扩欧求解,有解的话就求出$root$的值,然后$access$查询点再$splay(root)$,$root$的右儿子上的系数就是用$root$的值求询问点的值的对应系数。

  1 #include<string.h>
  2 #include<stdlib.h>
  3 #include<stdio.h>
  4 #include<math.h>
  5 //#include<assert.h>
  6 #include<algorithm> 
  7 #include<iostream>
  8 //#include<bitset>
  9 using namespace std;
 10 
 11 int n,m;
 12 #define maxn 30011
 13 const int mod=1e4+7;
 14 int exgcd(int a,int b,int &x,int &y)
 15 {
 16     if (!b) {x=1; y=0; return a;}
 17     else
 18     {
 19         int tmp=exgcd(b,a%b,y,x);
 20         y-=a/b*x; return tmp;
 21     }
 22 }
 23 int solve(int a,int b)
 24 {
 25     b=-b;
 26     if (a==0)
 27     {
 28         if (b==0) return -2;
 29         else return -1;
 30     }
 31     if (a<0) {a=-a; b=-b;}
 32     if (b<0) b+=mod;
 33     int x,y;exgcd(a,mod,x,y);
 34     x=((1ll*b*x%mod)+mod)%mod;
 35     return x;
 36 }
 37 
 38 struct LCT
 39 {
 40     struct Node
 41     {
 42         int fa,son[2];
 43         int biu;
 44         int k,b,kk,bb;
 45     }a[maxn];
 46     LCT() {a[0].k=a[0].kk=1;}
 47     void makeatree(int id,int k,int b)
 48     {
 49         a[id].fa=a[id].son[0]=a[id].son[1]=a[id].biu=0;
 50         a[id].k=a[id].kk=k; a[id].b=a[id].bb=b;
 51     }
 52     void up(int x)
 53     {
 54         if (!x) return;
 55         int &p=a[x].son[0],&q=a[x].son[1];
 56         a[x].kk=a[p].kk*1ll*a[x].k%mod*a[q].kk%mod;
 57         a[x].bb=a[q].bb+1ll*a[x].b*a[q].kk%mod+1ll*a[p].bb*a[q].kk%mod*a[x].k%mod; a[x].bb%=mod;
 58     }
 59     bool isroot(int x)
 60     {
 61         if (!a[x].fa) return 1;
 62         return (a[a[x].fa].son[0]!=x && a[a[x].fa].son[1]!=x);
 63     }
 64     void rotate(int x)
 65     {
 66         const int y=a[x].fa,z=a[y].fa;
 67         bool w=(x==a[y].son[0]);
 68         a[x].fa=z;
 69         if (!isroot(y)) a[z].son[y==a[z].son[1]]=x;
 70         a[y].son[w^1]=a[x].son[w];
 71         if (a[x].son[w]) a[a[x].son[w]].fa=y;
 72         a[x].son[w]=y;
 73         a[y].fa=x;
 74         up(y); up(z);
 75     }
 76     void splay(int x)
 77     {
 78         if (!x) return;
 79         while (!isroot(x))
 80         {
 81             const int y=a[x].fa,z=a[y].fa;
 82             if (!isroot(y))
 83             {
 84                 if ((y==a[z].son[0])^(x==a[y].son[0])) rotate(x);
 85                 else rotate(y);
 86             }
 87             rotate(x);
 88         }
 89         up(x);
 90     }
 91     void access(int x)
 92     {
 93         int y=0,tmp=x;
 94         while (x) {splay(x); a[x].son[1]=y; up(x); y=x; x=a[x].fa;}
 95         splay(tmp);
 96     }
 97     int findroot(int x)
 98     {
 99         while (a[x].fa) x=a[x].fa;
100         return x;
101     }
102     void link(int x,int y)
103     {
104         if (!y) return;
105         if (findroot(x)==findroot(y)) a[x].biu=y;
106         else
107         {
108             a[x].biu=0;
109             access(x);
110             a[x].fa=y;
111         }
112     }
113     void cut(int x,int y)
114     {
115         if (y==a[x].biu) a[x].biu=0;
116         else
117         {
118             access(x);
119             if (a[x].son[0]) a[a[x].son[0]].fa=0;
120             a[x].son[0]=0; up(x);
121         }
122     }
123     void modify(int x,int y,int z,int k,int b)
124     {
125         access(x);
126         a[x].k=k; a[x].b=b; up(x);
127         int root=x; while (a[root].son[0]) root=a[root].son[0];
128         cut(x,y); link(root,a[root].biu); link(x,z);
129     }
130     int query(int x)
131     {
132         int root=findroot(x);
133         while (a[root].son[0]) root=a[root].son[0]; splay(root);
134         int y=a[root].biu; access(y);
135         int tmp=solve(a[y].kk-1,a[y].bb);
136         if (tmp<0) return tmp;
137         tmp=(1ll*tmp*a[root].k+a[root].b)%mod;
138         if (x==root) return tmp;
139         access(x);
140         splay(root);
141         y=a[root].son[1];
142         return (a[y].kk*1ll*tmp+a[y].bb)%mod;
143     }
144 }t;
145 
146 int p[maxn];
147 int main()
148 {
149     scanf("%d",&n);
150     for (int i=1,x,y;i<=n;i++)
151     {
152         scanf("%d%d%d",&x,&p[i],&y);
153         t.makeatree(i,x,y);
154     }
155     for (int i=1;i<=n;i++) t.link(i,p[i]);
156     scanf("%d",&m);
157     int x,y,z,w; char c;
158     while (m--)
159     {
160         while ((c=getchar())!='A' && c!='C');
161         if (c=='A')
162         {
163             scanf("%d",&x);
164             printf("%d\n",t.query(x));
165         }
166         else
167         {
168             scanf("%d%d%d%d",&x,&y,&z,&w);
169             t.modify(x,p[x],z,y,w);
170             p[x]=z;
171         }
172     }
173     return 0;
174 }
View Code

 

posted @ 2018-01-18 08:58  Blue233333  阅读(446)  评论(0编辑  收藏  举报