题意:一排灯光有亮有暗,每个灯光有一个数值;
五种操作:
Q L R ss 求[L,R]区间中状态为ss的灯光的gcd;
I i value ss 在第i个灯光后插入一个数值为value状态为ss的灯光;
D i 将第i个灯光删除;
R i 改变第i个灯光的状态;
M i x 将第i个灯光的数值修改为x;
参考:http://wenku.baidu.com/link?url=EEwhlUPp2_U05mJEcbskt0_e3scLHpZ5gfS2s4OEvuAObTB2CgB4_TUroeccorOEGMxzzKk9SA_qt2w3K06Xbg6P1qLpR8PLgYmUSFHFOCG
思路:涉及数组的插入删除一般想到伸展树Splay,典型应用;一种二叉搜索树;
为了使整个查找时间更小,被查频率高的那些条目就应当经常处于靠近树根的位置。伸展树的优势就在于此;均摊复杂度O(logn)
伸展树的核心操作在于旋转,每次操作需要操作的数旋转到靠近根节点的ch[ch[root][1]][0]位置;
超级棒的数据结构。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define Key_value ch[ch[root][1]][0] const int maxn=500010; const int inf=0x3f3f3f3f; int pre[maxn],ch[maxn][2],key[maxn],siz[maxn];//父节点、子节点、数值、子树大小 int root,tot1; int sum0[maxn],sum1[maxn]; //两种状态对应的当前gcd int st[maxn]; //该节点的on或off状态 int s[maxn],tot2; //内存池,容量 int a[maxn],status[maxn],n,q; long long gcd(long long a,long long b){ if(b==0) return a; return gcd(b,a%b); } void NewNode(int &r,int father,int k,int ss){ //建立节点 if(tot2) r=s[tot2--]; else r=++tot1; pre[r]=father; ch[r][0]=ch[r][1]=0; key[r]=k; //数值 st[r]=ss; //灯光状态 if(ss==0) sum0[r]=k,sum1[r]=0; else sum0[r]=0,sum1[r]=k; siz[r]=1; } void pushup(int r){ //更新父节点,向上更新 int lson=ch[r][0],rson=ch[r][1]; siz[r]=siz[lson]+siz[rson]+1; sum0[r]=sum1[r]=0; sum0[r]=gcd(sum0[lson],sum0[rson]); sum1[r]=gcd(sum1[lson],sum1[rson]); if(st[r]) sum1[r]=gcd(sum1[r],key[r]); else sum0[r]=gcd(sum0[r],key[r]); } void build(int &x,int l,int r,int father){ //二叉树建树 if(l>r) return; int mid=(l+r)/2; NewNode(x,father,a[mid],status[mid]); build(ch[x][0],l,mid-1,x); build(ch[x][1],mid+1,r,x); pushup(x); } void init(){ //初始化 root=tot1=tot2=0; ch[root][0]=ch[root][1]=siz[root]=pre[root]=0; sum0[root]=sum1[root]=0; NewNode(root,0,0,0); NewNode(ch[root][1],root,0,0); //建立根节点 for(int i=0;i<n;i++) scanf("%d%d",&a[i],&status[i]); build(Key_value,0,n-1,ch[root][1]); //建树 pushup(ch[root][1]); pushup(root); } void Rotate(int x,int kind){ //旋转 int y=pre[x]; ch[y][!kind]=ch[x][kind]; pre[ch[x][kind]]=y; if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y]=x; pre[x]=pre[y]; ch[x][kind]=y; pre[y]=x; pushup(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); } } } pushup(r); if(goal==0) root=r; } int Get_kth(int r,int k){ //查询中序遍历第k大 int t=siz[ch[r][0]]+1; if(t==k) return r; if(t>k) return Get_kth(ch[r][0],k); else return Get_kth(ch[r][1],k-t); } void Insert(int pos,int val,int ss){ Splay(Get_kth(root,pos+1),0); Splay(Get_kth(root,pos+2),root); NewNode(Key_value,ch[root][1],val,ss); pushup(ch[root][1]); pushup(root); } void erase(int r){ if(!r) return; s[++tot2]=r; erase(ch[r][0]); erase(ch[r][1]); } void Delete(int pos){ //删除节点 Splay(Get_kth(root,pos),0); Splay(Get_kth(root,pos+2),root); erase(Key_value); pre[Key_value]=0; Key_value=0; pushup(ch[root][1]); pushup(root); } void change(int pos){ //翻转 Splay(Get_kth(root,pos),0); Splay(Get_kth(root,pos+2),root); st[Key_value]^=1; pushup(Key_value); pushup(ch[root][1]); pushup(root); } void modify(int pos,int val){ //修改 Splay(Get_kth(root,pos),0); Splay(Get_kth(root,pos+2),root); key[Key_value]=val; pushup(Key_value); pushup(ch[root][1]); pushup(root); } int query(int l,int r,int ss){ //查询gcd int ans; Splay(Get_kth(root,l),0); Splay(Get_kth(root,r+2),root); if(ss==0) ans=sum0[Key_value]; else ans=sum1[Key_value]; if(ans==0) ans=-1; return ans; } int main(){ int i,j,k; char ch[15]; while(scanf("%d%d",&n,&q)!=EOF){ init(); while(q--){ scanf("%s",ch); if(ch[0]==‘Q‘){ int l,r,ss; scanf("%d%d%d",&l,&r,&ss); printf("%d\n",query(l,r,ss)); } else if(ch[0]==‘I‘){ int pos,val,ss; scanf("%d%d%d",&pos,&val,&ss); Insert(pos,val,ss); } else if(ch[0]==‘D‘){ int pos; scanf("%d",&pos); Delete(pos); } else if(ch[0]==‘R‘){ int pos; scanf("%d",&pos); change(pos); } else if(ch[0]==‘M‘){ int pos,val; scanf("%d%d",&pos,&val); modify(pos,val); } } } return 0; }
原文:http://www.cnblogs.com/dominatingdashuzhilin/p/4736625.html