您的位置:首页 > 其它

[LCT 线性模方程] BZOJ 2759 一个动态树好题

2016-04-07 18:40 423 查看
%%%PoPoQQQ:http://blog.csdn.net/popoqqq/article/details/40436165

“题目大意:给定n个形如xi=ki*x_pi+bi mod p的同余方程组 支持修改操作和求解操作

确实好题 感谢此题作者 顺便吐槽一下作者的Splay不加空节点太蛋疼了0.0

将每个点i的父亲设为pi 我们将会得到一座基环树林 将环上的一条边拆掉,在边的起始节点新开个域special_father记录这条边(P.S:好浪费 但是没办法)

于是我们得到了一座森林 显然可以用LCT来维护 每个节点的权值是个二元组(k,b),记录每个点关于答案的线性关系,合并时左侧代入右侧中

查询时将root的special_father进行Access+Splay操作 然后借助这个环通过EXGCD求出root->special_father的值 然后Access+Splay(x)代入出解

若环上k=1 讨论b 若b=0则无穷多解 否则无解 注意k=0时要加一些处理 正常求EXGCD求不出来

单点修改 有向图 没有标记 爽爆了!

修改x的父节点时需要讨论:

首先切掉原先的父节点

如果x是所在树的根 直接切掉special_father

如果x不是根,切掉x与父节点的联系,然后讨论x是否在环上

设x所在树的根节点为root

若root->special_father所在树的根不为root 则x在环上 将root的special_father变为root的fa节点

否则切断父节点完毕

然后讨论新的父节点f是否在x的子树中

若在,将x的special_father设为f

若不在,将x的fa设为f”

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define P 10007
using namespace std;
typedef long long ll;
typedef pair<ll,ll> abcd;

inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}

inline void read(int &x)
{
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline void read(ll &x)
{
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline void read(char &x){
for (x=nc();x!='A' && x!='C';x=nc());
}

namespace Math{
#define N 10007
inline abcd EXGCD(ll a,ll b){
if (a<b) { abcd ret=EXGCD(b,a); return abcd(ret.second,ret.first); }
if (!b) return abcd(1,0);
abcd ret=EXGCD(b,a%b);
return abcd(ret.second,ret.first-a/b*ret.second);
}
inline int Solve(ll A,ll B){
A%=N; B%=N;
if (!A && !B) return -2;
if (!A && B) return -1;
if (!B && A) return 0;
abcd E=EXGCD(A,N);
ll D=A*E.first+N*E.second,X;
if (B%D==0)
{
if (D!=1) return -2;
X=E.first*(B/D);
X=((X%(N/D))+N/D)%(N/D);
return X;
}
else
return -1;
}
}

struct data{
ll k,b;
data(int k=1,int b=0):k(k),b(b) { }
friend data operator + (const data &A,const data &B){
data ret;
(ret.k=A.k*B.k)%=P;
(ret.b=B.k*A.b+B.b)%=P;
return ret;
}
};

struct Splay{
struct node{
int size,idx;
node *p,*ch[2],*fat,*sf;
data dat,sum;
inline void setc(node *c,int d) { ch[d]=c; c->p=this; }
inline bool dir() { return p->ch[1]==this; }
inline void update() { size=ch[1]->size+ch[0]->size+1; sum=ch[0]->sum+dat+ch[1]->sum; }
}*null,Mem[30005];
Splay() { null=Mem; null->p=null->ch[0]=null->ch[1]=null->fat=null->sf=null; null->size=0; null->sum=data(1,0); }
inline void rot(node *x){
if (x==null || x->p==null) return;
bool d=x->dir(); node *p=x->p;
if (p->p!=null) p->p->setc(x,p->dir()); else x->p=null;
p->setc(x->ch[d^1],d); x->setc(p,d^1); p->update(); x->update(); swap(x->fat,p->fat);
}
inline void splay(node *x){
if (x==null) return;
while (x->p!=null)
if (x->p->p==null)
rot(x);
else
x->dir()==x->p->dir()?(rot(x->p),rot(x)):(rot(x),rot(x));
}
inline node *Access(node *x){
node *y=null;
while (x!=null)
{
splay(x);
x->ch[1]->p=null; x->ch[1]->fat=x;
x->setc(y,1); y->fat=null;
x->update();
y=x; x=x->fat;
}
return y;
}
inline void Link(node *x,node *y){
Access(x);
splay(x);
x->fat=y;
Access(x);
}
inline void Cut(node *x){
Access(x);
splay(x);
x->ch[0]->p=null; x->ch[0]=null;
x->fat=null; x->update();
}
inline node *Root(node *x){
Access(x);
splay(x);
node *y=x;
while (y->ch[0]!=null) y=y->ch[0];
return y;
}
inline bool Jud(node *x,node *y){
return Root(x)==Root(y);
}
inline data Query(node *x){
return Access(x)->sum;
}
}LCT;

int n;
Splay::node *pos[30005];

inline void Init(int n)
{
for (int i=1;i<=n;i++)
pos[i]=LCT.Mem+i,pos[i]->p=pos[i]->ch[0]=pos[i]->ch[1]=pos[i]->fat=pos[i]->sf=LCT.null,pos[i]->size=1,pos[i]->idx=i;
}

inline void PCut(Splay::node *x){
if (x==LCT.Root(x)){
x->sf=LCT.null; return;
}
Splay::node *rt=LCT.Root(x),*sf=rt->sf;
LCT.Cut(x);
if (!LCT.Jud(sf,rt))
{
rt->sf=LCT.null;
LCT.Link(rt,sf);
}
}

inline void PLink(Splay::node *x,Splay::node *y){
if (LCT.Root(y)==x){
x->sf=y; return;
}
LCT.Link(x,y);
}

int par[30005];

int main()
{
char order;
int ip,Q,u,ik,ib;
ll x0;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); Init(n);
for (int i=1;i<=n;i++)
{
read(pos[i]->dat.k); read(par[i]); read(pos[i]->dat.b); pos[i]->update();
}
for (int i=1;i<=n;i++)
PLink(pos[i],pos[par[i]]);
read(Q);
while (Q--)
{
read(order);
if (order=='A')
{
read(u);
Splay::node *sf=LCT.Root(pos[u])->sf;
data ret=LCT.Query(sf);
ret.b=(-ret.b+P)%P;
ret.k=(ret.k-1+P)%P;
x0=Math::Solve(ret.k,ret.b);
if (x0!=-1 && x0!=-2)
{
ret=LCT.Query(pos[u]);
(x0=x0*ret.k+ret.b)%=P;
}
printf("%lld\n",x0);
}
else
{
read(u); read(ik); read(ip); read(ib);
PCut(pos[u]);
LCT.splay(pos[u]);
pos[u]->dat=data(ik,ib); pos[u]->update();
PLink(pos[u],pos[ip]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: