HDU 4453 (splay 插入删除翻转区间加单点查)

//白色上的模板,先静态申请结构体数组,再动态使用,时间应该更快;还有个小技巧,它的空指针用真实的null指针代替,这样即使访问了null的内容也没关系,减少出错的可能性
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;

struct Node {
  Node *ch[2];
  int s;
  int flip;
  int v;
  int add;
  int cmp(int k) const {
    int d = k - ch[0]->s;
    if(d == 1) return -1;
    return d <= 0 ? 0 : 1;
  }
  void maintain() {
    s = ch[0]->s + ch[1]->s + 1;
  }
  void pushdown() {
    if(flip) {
      flip = 0;
      swap(ch[0], ch[1]);
      ch[0]->flip = !ch[0]->flip;
      ch[1]->flip = !ch[1]->flip;
    }
    if(add){
        v+=add;
        ch[0]->add+=add;
        ch[1]->add+=add;
        add=0;
    }
  }
};

Node *null = new Node();

void rotate(Node* &o, int d) {
  Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o;
  o->maintain(); k->maintain(); o = k;
}

void splay(Node* &o, int k) {
  o->pushdown();
  int d = o->cmp(k);
  if(d == 1) k -= o->ch[0]->s + 1;
  if(d != -1) {
    Node* p = o->ch[d];
    p->pushdown();
    int d2 = p->cmp(k);
    int k2 = (d2 == 0 ? k : k - p->ch[0]->s - 1);
    if(d2 != -1) {
      splay(p->ch[d2], k2);
      if(d == d2) rotate(o, d^1); else rotate(o->ch[d], d);
    }
    rotate(o, d^1);
  }
}

// 合并left和right。假定left的所有元素比right小。注意right可以是null,但left不可以
Node* merge(Node* left, Node* right) {
  splay(left, left->s);
  left->ch[1] = right;
  left->maintain();
  return left;
}

// 把o的前k小结点放在left里,其他的放在right里。1<=k<=o->s。当k=o->s时,right=null
void split(Node* o, int k, Node* &left, Node* &right) {
  splay(o, k);
  left = o;
  right = o->ch[1];
  o->ch[1] = null;
  left->maintain();
}

const int maxn = 200000 + 10;
int a[maxn];
struct Splay {
  int n;
  Node seq[maxn];
  Node *root;
  Node* newNode(int v=0){
      Node* ret=&seq[++n];
      ret->v=v;
      ret->ch[0]=ret->ch[1]=null;
      ret->flip=ret->add=0;
      ret->s=1;
      return ret;
  }
  Node* build(int sz) {
    if(!sz) return null;
    Node* L = build(sz/2);
    Node* o = &seq[++n];
    o->v = a[n]; // 节点编号
    o->ch[0] = L;
    o->ch[1] = build(sz - sz/2 - 1);
    o->flip = o->s = o->add = 0;
    o->maintain();
    return o;
  }

  void init(int sz) {
    n = 0;
    null->s = 0;
    root = build(sz);
  }
}T;
#include<cstring>
#define rep(i,n) for(int i=0;i<n;i++)
#define fab(i,a,b) for(int i=a;i<=b;i++)
#define sf scanf
#define pf printf
vector<int> ans;
void print(Node* o) {
  if(o != null) {
    o->pushdown();
    print(o->ch[0]);
    ans.push_back(o->v);
    print(o->ch[1]);
  }
}

void debug(Node* o) {
  if(o != null) {
    o->pushdown();
    debug(o->ch[0]);
    printf("%d ", o->v-1);
    debug(o->ch[1]);
  }
}
int n,M,k2,k1;
void bug(){
    ans.clear();
    puts("bug");
    print(T.root);
    rep(i,ans.size())pf("%d ",ans[i]);pf("\n");
}
void init(){
   fab(i,1,n)sf("%d",&a[i]);
   T.init(n);
}
void Query(){
    splay(T.root,1);
    T.root->pushdown();
    pf("%d\n",T.root->v);
}
void Add(int x){
    T.root->pushdown();
    if(k2>=T.root->s){
        T.root->add+=x;
    }else{
        splay(T.root,k2+1);
        T.root->ch[0]->add+=x;
        T.root->maintain();
    }
}
void Reverse(){
    T.root->pushdown();
    if(k1>=T.root->s){
        T.root->flip^=1;
    }else{
        splay(T.root,k1+1);
        T.root->ch[0]->flip^=1;
    }
    T.root->maintain();
}
void Insert(int x){
    T.root->pushdown();
    splay(T.root,1);
    splay(T.root->ch[1],1);
    T.root->ch[1]->pushdown();
    T.root->ch[1]->ch[0]=T.newNode(x);
    T.root->ch[1]->maintain();
    T.root->maintain();
}
void Delete(){
    T.root->pushdown();
    splay(T.root,2);
    T.root->ch[0]=null;
    T.root->maintain();
}
void Move(int x){
    if(x==2){
        splay(T.root,2);
        T.root->pushdown();
        Node* first=T.root->ch[0];
        T.root->ch[0]=null;
        T.root->maintain();
        splay(T.root,T.root->s);
        T.root->pushdown();
        T.root->ch[1]=first;
        T.root->maintain();
    }else if(x==1){
        splay(T.root,T.root->s-1);
        T.root->pushdown();
        Node* end=T.root->ch[1];
        T.root->ch[1]=null;
        T.root->maintain();
        splay(T.root,1);
        T.root->pushdown();
        T.root->ch[0]=end;
        T.root->maintain();
    }
}
void solve(){
   char op[100];
   while(M--){
       scanf("%s",op);
       if(!strcmp(op,"query")){
           Query();
       }else if(!strcmp(op,"add")){
           int x;
           sf("%d",&x);
           Add(x);
       }else if(!strcmp(op,"bug")){
           bug();
       }else if(!strcmp(op,"reverse")){
           Reverse();
       }else if(!strcmp(op,"insert")){
           int x;sf("%d",&x);
           Insert(x);
       }else if(!strcmp(op,"delete")){
           Delete();
       }else if(!strcmp(op,"move")){
           int x;sf("%d",&x);
           Move(x);
       }
   }
}
int main(){
    int cas=1;
  while(~scanf("%d%d%d%d",&n,&M,&k1,&k2)&&(n+M+k1+k2)){
      pf("Case #%d:\n",cas++);
      init();
      solve();
  }
  return 0;
}
时间: 2024-11-05 14:55:11

HDU 4453 (splay 插入删除翻转区间加单点查)的相关文章

hdu 1754 splay tree伸展树 初战(单点更新,区间属性查询)

题意:与区间查询点更新,点有20W个,询问区间的最大值.曾经用线段树,1000+ms,今天的伸展树,890没ms,差不多. 第一次学习伸展树,一共花了2个单位时间,感觉伸展树真很有用,也很好玩.现在只学了一点点.切个点更新试试. 大致思路:用编号(数组)作为树的键值建树,每插一个数,沿路节点更新最大值(每个结点有一个附加信息标记以之为子树的树所有点的最大值).所以,查询时[i,j],只要把i-1伸展到树根,把j+1伸展到I-1下面,那么j+1的左子树就是要的区间了!查该子树根值信息即可(特判端点

HDU 5349 动态插入删除查询数据-multiset

题意:动态的插入删除查询数据,允许数据重复 分析:一看就是个multiset,直接做.STL大法好. 代码: #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<vector> #include<set> using namespace std; int n; int a; multiset<int> s; i

hdu 4031 Attack(树状数组区间更新单点求值&amp;暴力)

Attack Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 1890    Accepted Submission(s): 554 Problem Description Today is the 10th Annual of "September 11 attacks", the Al Qaeda is about to

hdu 4031 Attack(树状数组区间更新单点求值&amp;amp;暴力)

Attack Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 1890    Accepted Submission(s): 554 Problem Description Today is the 10th Annual of "September 11 attacks", the Al Qaeda is about to

树状数组2 - 区间加 单点求和

树状数组 = O(logn) 单点修改 ,O(logn) 区间查询 如果要做到 区间修改 单点查询 我们就要加入差分的思想 用树状数组记录数组的差分 然后对差分进行前缀和就可以得到单点的数据 //ios::sync_with_stdio(false); #include<bits/stdc++.h> #define ll long long using namespace std; const int MAXN = 500010; int n,m; ll C[MAXN]; ll lowbit(

hdu 4453 约会安排(线段树区间合并)

约会安排 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 433    Accepted Submission(s): 145 Problem Description 寒假来了,又到了小明和女神们约会的季节. 小明虽为屌丝级码农,但非常活跃,女神们常常在小明网上的大段发言后热情回复“呵呵”,所以,小明的最爱就是和女神们约会.与此同时,也有

HDU 5861 Road(线段树 区间修改 单点查询)

Road Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1132    Accepted Submission(s): 309 Problem Description There are n villages along a high way, and divided the high way into n-1 segments. E

[用CDQ分治解决区间加&amp;区间求和]【习作】

[前言] 作为一个什么数据结构都不会只会CDQ分治和分块的蒟蒻,面对区间加&区间求和这么难的问题,怎么可能会写线段树呢 于是,用CDQ分治解决区间加&区间求和这篇习作应运而生 [Part.I]区间加&区间求和的数据结构做法 [一]线段树 裸题... 1141ms #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include

AVL树非递归插入删除思路

AVL树是最先发明的自平衡二叉查找树.在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树.查找.插入和删除在平均和最坏情况下都是O(log n).增加和删除可能需要通过一次或多次树旋转来重新平衡这个树.AVL树得名于它的发明者G.M. Adelson-Velsky和E.M. Landis,他们在1962年的论文<An algorithm for the organization of information>中发表了它. 节点的平衡因子是它的左子树的高度减去它的右子树的