題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=4680
總體思路:初始化n棵splay樹,合并的時候需要用啟發學習法合并最佳化一下,前三個操作照做就行,第四個關於三角形的詢問需要西安判斷當前splay樹上有沒有3個節點,多餘三個的話就先枚舉最小的邊a和次小的邊b,然後尋找a+b的後繼c,找到的話答案加一,然後a = b,b=c遍曆一遍就行了,第五個關於GCD的操作就很簡單了,把[l,r]區間提取出來直接輸出GCD就行。下面上代碼:
#include<cstdio>#include<iostream>#include<cstring>#define L x->c[0]#define R x->c[1]#define KT root->c[1]->c[0]using namespace std;const int maxn = 300010;const int inf = 1000000007;int n,Type;int gcd(int a,int b){ if(a<0||a>=inf) return b; if(b<0||b>=inf) return a; return b == 0?a:gcd(b,a%b);}struct Node//id表示節點編號,g表示gcd,who表示節點屬於哪個splay樹{ struct Node *c[2],*fa; int id,size,g,val,who;}S[maxn],*null = &S[0];Node* Q[maxn];Node* ID[maxn];int scnt;struct snode{ int type; Node*root; inline Node *NewNode(int value,Node *p)//建立節點 { Node *e = S+(++scnt); e->val = value; e->id = scnt; e->size = 1; e->fa = p; e->g = value; e->c[0] = e->c[1] = null; ID[scnt] = e; return e; } inline void Update(Node *p)//更新節點資訊 { p->size = p->c[0]->size+p->c[1]->size+1; p->g = gcd(p->c[0]->g,p->c[1]->g); p->g = gcd(p->val,p->g); } inline void Rotate(Node *x,int k)//旋轉 { Node *y=x->fa; y->c[k]=x->c[!k]; y->c[k]->fa=y; x->fa=y->fa; if(y->fa->c[0]==y) y->fa->c[0]=x; else y->fa->c[1]=x; y->fa=x; x->c[!k]=y; Update(y); Update(x); if(root==y) root=x; } inline void Splay(Node *x,Node *y)//伸展 { while(x->fa!=y) { if(x->fa->fa==y) { if(x->fa->c[0]==x) Rotate(x,0); else Rotate(x,1); } else if(x->fa->fa->c[0]==x->fa) { if(x->fa->c[0]==x) Rotate(x->fa,0),Rotate(x,0); else Rotate(x,1),Rotate(x,0); } else { if(x->fa->c[1]==x) Rotate(x->fa,1),Rotate(x,1); else Rotate(x,0),Rotate(x,1); } } Update(x); } inline void Select(int k,Node *y)//旋轉第k個節點至y下方 { Node *x=root; while(k!=x->c[0]->size+1) { if(k<=x->c[0]->size) x=x->c[0]; else { k-=x->c[0]->size+1; x=x->c[1]; } }Splay(x,y); } inline void Init(int v)//初始化 { root = NewNode(v,null); type = ++Type; root->who = type; } inline void Delete(Node *x)//刪除節點 { Splay(x,null); Node *t = root; if(t->c[1]!=null) { root = t->c[1]; Select(1,null); root->c[0] = t->c[0]; if(root->c[0]!=null) root->c[0]->fa = root; } else { root = t->c[0]; } root->fa = null; if(root!=null)Update(root); } inline void Insert(Node *x)//插入節點 { x->c[0] = x->c[1] = null; insert(root,x); Splay(x,null); x->who = type; } inline void insert(Node* &x,Node* y) { if(x == null) { x = y; return; } if(y->val<=x->val) { insert(x->c[0],y); x->c[0]->fa = x; } else { insert(x->c[1],y); x->c[1]->fa = x; } Update(x); } inline void Change(Node* tmp,int v)//改變節點值 { Delete(tmp); tmp->val = v; Insert(tmp); } inline Node *FindSucc(Node *x,int v,int opt) { if(x == null)return x; if(x->val == v&&opt)return x; else if(x->val>v) { Node *tmp = FindSucc(x->c[0],v,opt); return tmp == null?x:tmp; } else { return FindSucc(x->c[1],v,opt); } } inline Node *FindSucc(int v,int opt)//尋找v的後繼,opt為1表示後繼可以等於v,否則不可以等於 { Node *tmp = FindSucc(root,v,opt); Splay(tmp,null); return tmp; } inline Node *FindPre(Node *x,int v) { if(x == null)return x; if(x->val<v) { Node *tmp = FindPre(x->c[1],v); return tmp == null?x:tmp; } else return FindPre(x->c[0],v); } inline Node *FindPre(int v)//尋找前驅 { Node* tmp = FindPre(root,v); Splay(tmp,null); return tmp; } inline void Merge(snode &tree)//合并 { int head,tail; head = tail = 0; tree.Select(1,null); tree.Select(tree.root->size,tree.root); Q[++tail] = tree.KT; while(head<tail) { Node* f = Q[++head]; if(f->c[0]!=null)Q[++tail] = f->c[0]; if(f->c[1]!=null)Q[++tail] = f->c[1]; Insert(f); f->who = type; } tree.KT = null; tree.Update(tree.root->c[1]); tree.Update(tree.root); } inline int SolveTri()//查詢4 { if(root->size<=4)return root->size-2; Select(2,null); int a = root->val; Select(3,null); int b = root->val; int ans = 2; while(true) { if(a+b>=inf)break; int c = FindSucc(a+b,1)->val; if(c>=inf||c == -1)break; a = b; b = c; ans++; } return ans; } inline int SolveGcd(int l,int r)//查詢5 { Node *pre = FindPre(l); Node *succ = FindSucc(r,0); Splay(pre,null); Splay(succ,root); return KT->g; } void vist(Node *x) { if(x != null) { printf("root %2d: left-son: %2d right-son: %2d size:%2d val=%2d gcd: %2d\n",x->id,x->c[0]->id,x->c[1]->id,x->size,x->val,x->g); vist(x->c[0]); vist(x->c[1]); } } void debug() { puts("******************************************"); vist(root); puts("*****************************************"); }}spt[maxn];void prepare(){ null->id = 0; null->c[0] = null->c[1] = null->fa = NULL; null->size = null->val = 0; null->g = -1; Type = 0; scnt = 0;}int main(){ int t,n,m,a,u,v,op,l,r,x,cas = 1; scanf("%d",&t); while(t--) { prepare(); printf("Case #%d:\n",cas++); scanf("%d%d",&n,&m); for(int i = 1;i<=n;i++) { spt[i].Init(-1); Node *tmp = spt[i].NewNode(inf,null); spt[i].Insert(tmp); } for(int i = 1;i<=n;i++) { scanf("%d",&a); Node *tmp = spt[i].NewNode(a,null); spt[i].Insert(tmp); } int tot = 0; while(m--) { scanf("%d",&op); if(op == 1) { scanf("%d%d",&u,&v); Node *t1 = ID[u+2*n]; Node *t2 = ID[v+2*n]; int tree1 = t1->who; int tree2 = t2->who; if(tree1 == tree2)continue; int size1 = spt[tree1].root->size; int size2 = spt[tree2].root->size; if(size1>size2)spt[tree1].Merge(spt[tree2]); else spt[tree2].Merge(spt[tree1]); } else if(op == 2) { scanf("%d%d",&u,&v); Node *t1 = ID[u+2*n]; Node *t2 = ID[v+2*n]; int tree1 = t1->who; int tree2 = t2->who; spt[tree1].Delete(t1); spt[tree2].Insert(t1); } else if(op == 3) { scanf("%d%d",&u,&x); Node *tmp = ID[u+2*n]; int tree = tmp->who; spt[tree].Change(tmp,x); } else if(op == 4) { scanf("%d",&u); Node *tmp = ID[u+2*n]; int tree = tmp->who; printf("%d\n",spt[tree].SolveTri()); } else { scanf("%d%d%d",&u,&l,&r); Node *tmp = ID[u+2*n]; int tree = tmp->who; printf("%d\n",spt[tree].SolveGcd(l,r)); } } } return 0;}