hdu 4680 About set 小记(毕竟是一天的时光啊)
Problem Description
Today Zhanyl (sister Zhan as you know) receives a task about set operation. Although she is very good at this task,
but you know she is very lazy so that she wants you to help her write a program to complete this task. Surly
Zhanyl is able to solve this question, but you know, she is just lazy ...
Here is the problem, you are given n numbers, each number i has a value A i, initially they are in different set.
Following there are m operations/querys.
The following is 5 possible kinds of oprations/querys:
1 u v: Union the set u belongs to and the set v belongs to.
2 u v: Delete u from its original set and add it to the set v belongs to.
3 u x: change the value of u to x. 1<=x<=10 9
4 u: query how many numbers you can choose most in set which u belongs to, so no three numbers can form a triangle.
5 u l r: query the gcd of the numbers between [l,r] in the set u belongs to, if there is no number between [l,r],you can suppose the answer is -1. 1<=l<=r<=109
Because Zhanyl is a good person, so she guarantee 1<=u,v<=n above.
You need to tell Zhanyl the answer to each query.
but you know she is very lazy so that she wants you to help her write a program to complete this task. Surly
Zhanyl is able to solve this question, but you know, she is just lazy ...
Here is the problem, you are given n numbers, each number i has a value A i, initially they are in different set.
Following there are m operations/querys.
The following is 5 possible kinds of oprations/querys:
1 u v: Union the set u belongs to and the set v belongs to.
2 u v: Delete u from its original set and add it to the set v belongs to.
3 u x: change the value of u to x. 1<=x<=10 9
4 u: query how many numbers you can choose most in set which u belongs to, so no three numbers can form a triangle.
5 u l r: query the gcd of the numbers between [l,r] in the set u belongs to, if there is no number between [l,r],you can suppose the answer is -1. 1<=l<=r<=109
Because Zhanyl is a good person, so she guarantee 1<=u,v<=n above.
You need to tell Zhanyl the answer to each query.
Input
The first line of the input is a single integer T which is the number of test cases.Then comes the T test cases .
For each test case, the first line contains two integer n and m, n is the number of set initially, m is the number
of operations/querys.
Following line contains n integers, A 1, A 2, ... , A n, the value of i-th number.
Following m lines, each line is a operation or query.
Note that 1<=n,m<=10 5, 1<=A i<=10 9
For each test case, the first line contains two integer n and m, n is the number of set initially, m is the number
of operations/querys.
Following line contains n integers, A 1, A 2, ... , A n, the value of i-th number.
Following m lines, each line is a operation or query.
Note that 1<=n,m<=10 5, 1<=A i<=10 9
各种操作如上。
大裸数据结构啊,比赛的时候想敲的,不过很长时间没写这种多
颗树合并的题,而且有一个最关键的启发式合并的地方想歪了,认为复杂度不行,就没敲,现在想想还真是后悔,只怪自己的思维还不够严谨,要是在比赛中敲,不管能不能AC,都会比赛后敲来的激情啊。
好歹花了一天时间,第一次全部手写splay树的所有函数,debug的时候过于自信就没去看那几个函数,而且还过了自己出的很多数据,后来看到了,就一点点改,一直到所有的bug都找到了(我认为的),交上去还是TLE,比较庆幸的是这次写没有像写10天津那个题一样,RE了好长一排(那是第一次写指针splay),很多结构调试起来还是轻松的,但是由于种种细节过多,导致我一开始就看出来的错误有一个地方没有修改好,然后就一直T。。
一些花絮::
TLE持续中。。。。。
TLE持续中。。。。。
实在是好忧桑啊。。。。。
这日子没法过了。。。。。
怎么办怎么办。。。。。。。。
继续埋头看代码。。。。。
找到了!!!!
再来一发,还是TLE。。。。。
MD,爆粗口了。。。。。
好吧,先去赚点钱吧!!!!都是正事啊。。。
教别人游泳的时候一直无法专心,,,,,明明没错啊,,,
晚上回到寝室,杰哥帮忙跑了一发100000的数据,竟然跑不出来。。
这不科学
然后仔细一看,有个地方写傻了,,,,
233333333333333333333333333333
我乃绝世大sb,不能直视啊。。。
然后怒交一发,AC了!!!!!!
这个题思路很简单的,就按照题目告诉的模拟就好了,真正好的数据结构题不该是这种大裸的题吧,,,
还是贴个代码吧。。。不过代码略微有些含蓄+混乱。。。切勿随意模仿
/* ********************************************** Author : wuyiqi Created Time: 2013-8-16 8:24:44 File Name : hdu 4680.cpp *********************************************** */ #pragma comment(linker,"/STACK:100000000,100000000") #include <cstring> #include <cstdio> #include <string> #include <iostream> using namespace std; #define L x->c[0] #define R x->c[1] #define KT root->c[1]->c[0] const int maxn = 300010; const int lim = 1000000000; inline int GCD(int a,int b) { if(a<0||a>lim) return b; if(b<0||b>lim) return a; return !b ? a : GCD(b,a%b); } struct node { struct node *c[2] , *fa; int id; int sz; int gcd; int val; int who; inline bool d() { return fa->c[0] == this; } inline void setc(int d,node *s) { c[d] = s; s->fa = this; } inline void up() { sz = c[0]->sz + c[1]->sz + 1; gcd = GCD(c[0]->gcd,c[1]->gcd); gcd = GCD(gcd,val); } inline void clear(node *null) { c[0] = c[1] = null; } }NODE[maxn] , *null = &NODE[0]; node* Q[maxn]; node* ID[maxn]; int Type; int n; int top; struct _x_x_{ int type; node* root; inline void Rotate(node *x,int f){ node *y = x->fa; y->setc(!f,x->c[f]); x->fa = y->fa; if(y->fa != null) y->fa->setc(!y->d(),x); x->setc(f,y); y->up(); } inline void Splay(node *x,node *goal) { while(x->fa!=goal) { if(x->fa->fa == goal) Rotate(x,x->d()); else { int f = x->fa->d(); x->d() == f ? Rotate(x->fa,f) : Rotate(x,!f); Rotate(x,f); } } x->up(); if(goal == null) { root = x; } } inline void RTO(int k,node *goal) { node *x = root; while(L->sz + 1 != k) { if(k < L->sz + 1) x = L; else { k -= L->sz + 1; x = R; } } Splay(x,goal); } inline node* new_node(node *fa,int v) { node *x = &NODE[++top]; x->id = top; x->c[0] = x->c[1] = null; x->sz = 1; x->val = v; x->gcd = v; x->fa = fa; ID[top] = x; return x; } inline void init(int v) { root = new_node(null,v); type = ++Type; root->who = type; } inline void Del_root() { node *t = root; if(t->c[1] != null) { root = t->c[1]; RTO(1,null); root->c[0] = t->c[0]; if(root->c[0] != null) root->c[0]->fa = root; } else { root = root->c[0]; } root->fa = null; if(root != null) root->up(); } inline void Delete(node *x) { Splay(x,null); Del_root(); } inline void Insert(node *x) { x->clear(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; } x->up(); } inline void Insert(int v) { node *x = new_node(null,v); insert(root,x); Splay(x,null); x->who = type; } inline void Change(int u,int v) { node *tmp = ID[u+2*n]; Splay(tmp,null); Del_root(); tmp->val = v; Insert(tmp); } node *find_succ(node *x,int v) { if(x == null) return x; if(x->val == v) return x; else if(x->val > v) { node *tmp = find_succ(x->c[0],v); return tmp == null ? x : tmp; }else { return find_succ(x->c[1],v); } } inline int find_succ(int v){ node* tmp = find_succ(root,v); Splay(tmp,null) ; return tmp->val; } inline int Gao() { if(root->sz <= 4) return root->sz - 2; RTO(2,null); int a = root->val; RTO(3,null); int b = root->val; int ans = 2; while(true){ if(a + b > lim) break; int c = find_succ(a+b); if(c > lim || c == -1) break; a = b; b = c; ans++; } return ans; } void vist(node *x) { if(x != null) { printf("节点 %2d: 左儿子: %2d 右儿子: %2d sz:%2d val=%2d gcd: %2d\n",x->id,x->c[0]->id,x->c[1]->id,x->sz,x->val,x->gcd); vist(x->c[0]); vist(x->c[1]); } } void debug() { puts("******************************************"); vist(root); puts("*****************************************"); } node *Find_pre(node *x,int v) { if(x == null) return x; if(x->val < v) { node *tmp = Find_pre(x->c[1],v); return tmp == null ? x : tmp; } else { return Find_pre(x->c[0],v); } } node *Find_pre(int v) { node* tmp = Find_pre(root,v); Splay(tmp,null); return tmp; } node *Find_succ(node *x,int v) { if(x == null) return x; if(x->val > v) { node *tmp = Find_succ(x->c[0],v); return tmp == null ? x : tmp; } else { return Find_succ(x->c[1],v); } } node *Find_succ(int v) { node* tmp = Find_succ(root,v); Splay(tmp,null); return tmp; } void Assert(string s) { cout<<s<<endl; } int Solve(int l,int r) { node *pre = Find_pre(l); node *succ = Find_succ(r); if(pre == null || succ == null) Assert("越界了"); // printf("preid=%d succid=%d\n",pre->id,succ->id); // pre : the first element strictly less than l // succ: the first element strictly bigger than r Splay(pre,null); Splay(succ,root); return KT->gcd; } void Merge(_x_x_ &tree) { int head = 0, tail = 0; tree.RTO(1,null); tree.RTO(tree.root->sz,tree.root); Q[++tail] = tree.KT; while(head < tail) { node *fr = Q[++head]; if(fr->c[0] != null) Q[++tail] = fr->c[0]; if(fr->c[1] != null) Q[++tail] = fr->c[1]; Insert(fr);//此处吐血了一整天,上面的改回来了,这里却没改insert(root,fr); fr->who = type; } tree.KT = null; tree.root->c[1]->up(); tree.root->up(); } }spt[maxn]; void prepare() { null->id = 0; null->c[0] = null->c[1] = null->fa = NULL; null->sz = null->val = 0; null->gcd = -1; Type = 0; top = 0; } int main() { // freopen("input.txt","r",stdin); // freopen("cmp.txt","w",stdout); int t,m,ca=1,op,u,v,l,r,x; scanf("%d",&t); while(t--) { prepare(); scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++){ spt[i].init(-1); spt[i].Insert(lim+1); } for(int i = 1,a; i <= n; i++) { scanf("%d",&a); spt[i].Insert(a); } int tot = 0; printf("Case #%d:\n",ca++); while(m--) { scanf("%d",&op); if(op == 1) { scanf("%d%d",&u,&v); node *tmp1 = ID[u+2*n] , *tmp2 = ID[v+2*n]; int tree1 = tmp1->who; int tree2 = tmp2->who; if(tree1 == tree2) continue; int sz1 = spt[tree1].root->sz; int sz2 = spt[tree2].root->sz; if(sz1 > sz2) { spt[tree1].Merge(spt[tree2]); } else { spt[tree2].Merge(spt[tree1]); } // if(spt[tree1].root->sz < 2 || spt[tree2].root->sz < 2){ // return 0; // break; // } // spt[tree1].debug(); } else if(op == 2) { scanf("%d%d",&u,&v); node *tmp1 = ID[u+2*n] , *tmp2 = ID[v+2*n]; int tree1 = tmp1->who; int tree2 = tmp2->who; // spt[tree1].debug(); spt[tree2].debug(); spt[tree1].Delete(tmp1); // if(spt[tree2].root->sz < 2) return 0; spt[tree2].Insert(tmp1); // spt[tree1].debug(); spt[tree2].debug(); } else if(op == 3) { scanf("%d%d",&u,&x); node *tmp = ID[u+2*n]; int tree = tmp->who; spt[tree].Change(u,x); } else if(op == 4) { scanf("%d",&u); node *tmp = ID[u+2*n]; int tree = tmp->who; printf("%d\n",spt[tree].Gao()); } else { scanf("%d%d%d",&u,&l,&r); node *tmp = ID[u+2*n]; int tree = tmp->who; // printf("id=%d tree=%d\n",tmp->id,tree); printf("%d\n",spt[tree].Solve(l,r)); } } } return 0; }