码迷,mamicode.com
首页 > 其他好文 > 详细

zoj 3765 Lights(伸展树)

时间:2015-08-17 15:26:45      阅读:107      评论:0      收藏:0      [点我收藏+]

标签:

题意:一排灯光有亮有暗,每个灯光有一个数值;

       五种操作:

       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;
}

 

zoj 3765 Lights(伸展树)

标签:

原文地址:http://www.cnblogs.com/dominatingdashuzhilin/p/4736625.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!