题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3765
昨天比赛的时候,别人都把这题KO我却只能干瞪眼,虽然感觉是伸展树,可是之前一直没真正去学这东西。
事后学了下这个东西马上回去ZOJ把这题QJ了!
伸展树(Splay Tree)这东西太神奇啦!
我是看cxlove大牛的文章学习的:http://blog.csdn.net/acm_cxlove/article/details/7815019
关于ZOJ这题,呃,题目有点繁琐,但其实还是很裸的Splay,只是记录最大公约数的时候要分成01两个状态来记录。
PS:感觉部分自己写的代码还是有点乱。。。
#include<cstdio>
#include<cstring>
#define maxn 300010
#define Key_value ch[ch[root][1]][0]
int gcd(int x, int y){
if(x<y){
x^=y; y^=x; x^=y;
}
if(y<=0) return x;
int z=x%y;
while(z){
x=y; y=z; z=x%y;
}
return y;
}
int n, q, a[maxn], b[maxn];
int root, tot, ch[maxn][2];
int size[maxn], key[maxn], pre[maxn], g[maxn][2], st[maxn];
void Push_Up(int r){
int left = ch[r][0];
int right = ch[r][1];
size[r] = size[left]+size[right]+1;
g[r][0] = gcd(g[left][0], g[right][0]);
g[r][1] = gcd(g[left][1], g[right][1]);
g[r][st[r]] = gcd(g[r][st[r]], key[r]);
}
void NewNode(int& r,int k,int s,int father){
r=++tot;
key[r]=k;
pre[r]=father;
st[r]=s;
ch[r][0]=ch[r][1]=0;
}
void Build(int& r,int L,int R,int father){
if(L>R) return;
int mid=(L+R)>>1;
NewNode(r,a[mid],b[mid],father);
Build(ch[r][0],L,mid-1,r);
Build(ch[r][1],mid+1,R,r);
Push_Up(r);
}
void init(){
root=tot=0;
ch[root][0]=ch[root][1]=pre[root]=size[root]=st[root]=0;
g[root][0]=g[root][1]=-1;
NewNode(root,-1,0,0);
NewNode(ch[root][1],-1,0,root);
size[root]=2;
for(int i=1; i<=n; i++){
scanf("%d %d", a+i, b+i);
}
Build(Key_value, 1, n, ch[root][1]);
Push_Up(ch[root][1]);
Push_Up(root);
}
int Get_Kth(int r, int k){
int t=size[ch[r][0]];
if(t==k-1) return r;
if(t>=k) return Get_Kth(ch[r][0],k);
else return Get_Kth(ch[r][1],k-t-1);
}
int Get_Min(int r){
while(ch[r][0]){
r=ch[r][0];
}
return r;
}
void Rotate(int r, int kind){
int y = pre[r];
ch[y][!kind] = ch[r][kind];
pre[ch[r][kind]]=y;
if(pre[y])
ch[pre[y]][ch[pre[y]][1]==y]=r;
pre[r]=pre[y];
ch[r][kind]=y;
pre[y]=r;
Push_Up(y);
}
void Splay(int r, int goal){
while(pre[r]!=goal){
if(pre[pre[r]]==goal){
Rotate(r, ch[pre[r]][0]==r);
}
else{
int y=pre[r];
int kind = (ch[pre[y]][0]==y);
if(ch[y][kind]==r){
Rotate(r,!kind);
Rotate(r,kind);
}
else{
Rotate(y,kind);
Rotate(r,kind);
}
}
}
Push_Up(r);
if(!goal) root=r;
}
void Query(int a, int b, int c){
int x = Get_Kth(root, a);
int y = Get_Kth(root, b+2);
Splay(x, 0);
Splay(y, root);
printf("%d\n", g[Key_value][c]);
}
void Insert(int a, int b, int c){
int x = Get_Kth(root,a+1);
Splay(x, 0);
int y = Get_Min(ch[root][1]);
Splay(y, root);
int left=x, right=y;
NewNode(root,b,c,0);
ch[root][0]=left;
ch[root][1]=right;
ch[left][1]=0;
pre[left]=root;
pre[right]=root;
Push_Up(left);
Push_Up(root);
}
void Del(int a){
int x = Get_Kth(root, a+1);
Splay(x, 0);
int y = Get_Min(ch[root][1]);
Splay(y, root);
pre[ch[x][0]] = y;
ch[y][0] = ch[x][0];
pre[y]=0;
root=y;
Push_Up(y);
}
void Turn(int a){
int x = Get_Kth(root, a+1);
Splay(x, 0);
st[x]^=1;
Push_Up(x);
}
void Change(int a, int b){
int x = Get_Kth(root, a+1);
Splay(x, 0);
key[x]=b;
Push_Up(x);
}
inline void IN(int& x){
x=0;
char ch=getchar();
while(ch<48 || ch>57) ch=getchar();
while(ch>=48 && ch<=57){
x=x*10+ch-48;
ch=getchar();
}
}
int main(){
while(~scanf("%d %d", &n, &q)){
init();
char op[10];
int x, y, z;
while(q--){
scanf("%s", op);
if(op[0]=='Q'){
IN(x); IN(y); IN(z);
Query(x,y,z);
}
else if(op[0]=='I'){
IN(x); IN(y); IN(z);
Insert(x,y,z);
}
else if(op[0]=='D'){
IN(x);
Del(x);
}
else if(op[0]=='R'){
IN(x);
Turn(x);
}
else{
IN(x); IN(y);
Change(x,y);
}
}
}
return 0;
}