【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

HINT

Source

By 范浩强

确实是好题,就是不会做
看了Po姐姐的题解.Po姐题解,写得很详细.
主要就是这个题不是简单地树结构,可能成环,所以要多维护一个新的父亲节点,然后扩欧+LCT.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 30010
#define P 10007
#define GET (ch>='0'&&ch<='9')
#define is_root(x) (tree[tree[x].fa].ch[0]!=x&&tree[tree[x].fa].ch[1]!=x)
using namespace std;
int n,q,dfn;
int vis[MAXN],p[MAXN];
int sta[MAXN],top;
struct data
{
    int k,b;
    friend data operator +(const data &x,const data &y) {   return (data){x.k*y.k%P,(x.b*y.k+y.b)%P};   }
    int calc(int x) {   return (k*x+b)%P;   }
};
struct node {   int x,y;    };
struct tree
{
    int ch[2],fa,fa2;
    data val,sum;
    bool rev;
}tree[MAXN];
inline void push_up(int x)  {   tree[x].sum=tree[tree[x].ch[0]].sum+tree[x].val+tree[tree[x].ch[1]].sum;    }
inline void push_down(int x)
{
    if (!x) return;
    if (tree[x].rev)
    {
        tree[tree[x].ch[0]].rev^=1;tree[tree[x].ch[1]].rev^=1;
        swap(tree[x].ch[0],tree[x].ch[1]);tree[x].rev^=1;
    }
}
inline void rot(int x)
{
    int y=tree[x].fa,z=tree[y].fa,l=(tree[y].ch[1]==x),r=l^1;
    if (!is_root(y))    tree[z].ch[tree[z].ch[1]==y]=x;
    tree[y].fa=x;tree[tree[x].ch[r]].fa=y;tree[x].fa=z;
    tree[y].ch[l]=tree[x].ch[r];tree[x].ch[r]=y;
    push_up(y);push_up(x);
}
inline void Splay(int x)
{
    top=0;sta[++top]=x;
    for (int i=x;!is_root(i);i=tree[i].fa)  sta[++top]=tree[i].fa;
    while (top) push_down(sta[top--]);
    while (!is_root(x))
    {
        int y=tree[x].fa,z=tree[y].fa;
        if (!is_root(y))
        {
            if ((tree[y].ch[0]==x)^(tree[z].ch[0]==y))  rot(x);
            else    rot(y);
        }
        rot(x);
    }
}
inline void access(int x)   {   for (int i=0;x;i=x,x=tree[x].fa)    Splay(x),tree[x].ch[1]=i,push_up(x);    }
inline void make_root(int x)    {   access(x);Splay(x);tree[x].rev^=1;  }
inline void link(int x,int y)   {   make_root(x);tree[x].fa=y;  }
inline void cut(int x,int y)    {   make_root(x);access(y);Splay(y);tree[x].fa=tree[y].ch[0]=0;push_up(y);  }
inline void split(int x,int y)  {   make_root(x);access(y);Splay(y);    }
inline int find_root(int x) {   for (access(x),Splay(x);tree[x].ch[0];x=tree[x].ch[0]);return x;    }
node exgcd(int x,int y)
{
    if  (!y)    return (node){1,0};
    node t=exgcd(y,x%y);return (node){t.y,t.x-x/y*t.y};
}
inline int inv(int x)   {   return (exgcd((x+P)%P,P).x+P)%P;    }
inline int query(int x)
{
    int root=find_root(x);
    access(tree[root].fa2);Splay(tree[root].fa2);
    int k=tree[tree[root].fa2].sum.k,b=tree[tree[root].fa2].sum.b;
    if (k==1)   return b==0?-2:-1;
    int tmp=(P-b)*inv(k-1)%P;
    access(x);Splay(x);return tree[x].sum.calc(tmp);
}
inline void modify(int x,int k,int b,int f)
{
    int root=find_root(x);
    tree[x].val.k=k;tree[x].val.b=b;push_up(x);
    if (x==root)    tree[x].fa2=0;
    else
    {
        access(x);Splay(x);
        tree[tree[x].ch[0]].fa=0;tree[x].ch[0]=0;
        push_up(x);
        if (find_root(tree[root].fa2)!=root)
            access(root),Splay(root),
            tree[root].fa=tree[root].fa2,tree[root].fa2=0;
    }
    access(x);Splay(x);
    if (find_root(f)==x)    tree[x].fa2=f;
    else    tree[x].fa=f;
}
void dfs(int x)
{
    vis[x]=dfn;
    if (vis[p[x]]==dfn) {   tree[x].fa2=p[x];return;    }
    tree[x].fa=p[x];
    if (!vis[p[x]]) dfs(p[x]);
}
inline void in(int &x)
{
    char ch=getchar();x=0;
    while (!GET)    ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();
}
int main()
{
    in(n);int x,k,f,b;char ch[3];
    tree[0].val.k=tree[0].sum.k=1;tree[0].val.b=tree[0].sum.b=0;
    for (int i=1;i<=n;i++)  
        in(k),in(f),in(b),p[i]=f,
        tree[i].val.k=k,tree[i].val.b=b,
        tree[i].sum.k=k,tree[i].sum.b=b;
    for (int i=1;i<=n;i++)  if (!vis[i])    ++dfn,dfs(i);
    for (in(q);q;q--)
    {
        scanf("%s",ch);
        if (ch[0]=='A') in(x),printf("%d\n",query(x));
        else    in(x),in(k),in(f),in(b),modify(x,k,b,f);
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值