<6.21>数据结构整理(Treap,线段树,主席树)

HDU 3726 Graph and Queries

http://acm.hdu.edu.cn/showproblem.php?pid=3726

离线逆序操作启发式合并找第K大值

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <climits>
using namespace std;
#define N 50005

struct Treap
{
  int root[N] , priority[N] , child[N][2];
  int key[N];
  int Size[N] , cnt[N];
  vector<int> del;
  Treap()
  {
    priority[0] = 0x7FFFFFFF;
  }
  void clear()
  {
    del.clear();
  }
  int size(int x)
  {
    return Size[root[x]];
  }
  void update(int x)
  {
    Size[x] = Size[child[x][0]] + Size[child[x][1]] + cnt[x];
  }

  void rotate (int& x , int t)
  {
    int y = child[x][t];
    child[x][t] = child[y][t ^ 1];
    child[y][t ^ 1] = x;
    update(x) , update(y);
    x = y;
  }

  void __insert(int& x , int k)
  {
    if (x)
    {
      if (key[x] == k)
        ++ cnt[x];
      else
      {
        int t = key[x] < k;
        __insert(child[x][t] , k);
        if (priority[child[x][t]] < priority[x])
           rotate(x , t);
      }
    }
    else
    {
      x = del.back();
      del.pop_back();
      key[x] = k;
      cnt[x] = 1;
      priority[x] = rand() << 15 | rand();
      child[x][0] = child[x][1] = 0;
    }
    update(x);
  }

  void __erase(int& x , int k)
  {
    //if (!x) return;
    if (key[x] == k)
    {
      if (cnt[x] > 1)
        -- cnt[x];
      else
      {
        if (!child[x][0] && !child[x][1])
        {
          del.push_back(x);
          cnt[x] = 0 , x = 0;
          return;
        }
        int t = priority[child[x][0]] > priority[child[x][1]];
        rotate(x , t);
        __erase(x , k);
      }
    }
    else
      __erase(child[x][key[x] < k] , k);
    update(x);
  }
  int __getKth(int& x , int k)
  {
    if (k <= Size[child[x][0]])
      return __getKth(child[x][0] , k);
    k -= Size[child[x][0]] + cnt[x];
    if (k <= 0)  return key[x];
    return __getKth(child[x][1] , k);
  }
  void merge(int& x , int& y)
  {
    if (child[x][0]) merge(child[x][0] , y);
    if (child[x][1]) merge(child[x][1] , y);
    int z = key[x];
    while(cnt[x] > 1)
    {
      __erase(x , z);
      if (z != -1 << 30)
        __insert(y , z);
    }
    __erase(x , z);
    if (z != -1 << 30)
      __insert(y , z);
  }
};

#define Nnum 20005
#define Mnum 60005
#define Qnum 500005
int n , m , Q , ca;
Treap T;
struct edge
{
  int x , y;
  bool f;
}e[Mnum];
struct query
{
  int id , x , y;
}q[Qnum];
int f[Nnum] , a[Nnum];
int getf(int x) {return x == f[x] ? x : f[x] = getf(f[x]);}

void work()
{
  int i , j , x , y , z;
  char str[3];
  for (i = 1 ; i <= n ; ++ i)
    scanf("%d",&a[i]) , f[i] = i;
  for (i = 1 ; i <= m ; ++ i)
    scanf("%d%d",&e[i].x, &e[i].y) , e[i].f = 0;
  Q = 0 , T.clear();
  for (i = n + n/2; i > 0 ; -- i)
    T.del.push_back(n + i);
  while (scanf("%s" , str) , str[0] != 'E')
  {
    if (str[0] == 'D')
      q[++ Q].id = 0;
    if (str[0] == 'Q')
      q[++ Q].id = 1;
    if (str[0] == 'C')
      q[++ Q].id = 2;
    scanf("%d",&q[Q].x);
    if (q[Q].id)
      scanf("%d",&q[Q].y);

    if (q[Q].id == 0)
    {
      e[q[Q].x].f = 1;
    }
    if (q[Q].id == 2)
    {
      q[Q].y -= a[q[Q].x];
      a[q[Q].x] += q[Q].y;
    }
  }
  for (i = 1 ; i <= m ; ++ i)
    if (!e[i].f)
       f[getf(e[i].x)] = getf(e[i].y);

  for (i = 1 ; i <= n ; ++ i)
  {
    T.root[i] = i;
    T.cnt[i] = 0 , T.priority[i] = INT_MIN , T.key[i] = -1 << 30;
    T.child[i][0] = T.child[i][1] = 0;
    x = i;
    T.__insert(T.root[i] , a[i]);
  }
  for (i = 1 ; i <= n ; ++ i)
    if (getf(i) != i)
    {
      T.__erase(T.root[i] , a[i]) ;
      T.__insert(T.root[getf(i)] , a[i]);
    }

  long long ans = 0 , tot = 0;
  for (i = Q ; i > 0 ; -- i)
  {
    if (q[i].id == 0)
    {
      j = q[i].x;
      x = getf(e[j].x) , y = getf(e[j].y);
      if (x == y) continue;
      if (T.size(x) > T.size(y))
        swap(x , y);
      f[x] = y;
      T.merge(T.root[x] , T.root[y]);
    }
    if (q[i].id == 1)
    {
      x = getf(q[i].x) , ++ tot;
      j = T.size(x);
      if (q[i].y < 1 || q[i].y > j)
        continue;
      ans += T.__getKth(T.root[x] , j - q[i].y + 1);
    }
    if (q[i].id == 2)
    {
      x = getf(q[i].x);
      T.__erase(T.root[x] , a[q[i].x]);
      a[q[i].x] -= q[i].y;
      T.__insert(T.root[x] , a[q[i].x]);
    }
  }
  printf("Case %d: %lf\n" , ++ ca , tot ? 1.0 * ans / tot : 0.0);
}

int main()
{
  //srand((unsigned int)time(0));
  while (scanf("%d%d",&n,&m) , n || m)
  //int _; cin >> _;while (_--)
    work();
  return 0;
}

SCU4285

http://cstest.scu.edu.cn/soj/problem.action?id=4285

可以拿set简单过的,用Treap写了写体会了一下如何进行垃圾回收

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
#define N 10005

struct Treap
{
  int root , nodecnt , priority[N] , child[N][2];
  int key[N];
  int Size[N] , cnt[N];
  vector<int> del;
  Treap(){
    del.clear();
    root = 0 , nodecnt = 1;
    priority[0] = key[0] = 1 << 30;
    Size[0] = 0;
  }
  void clear()
  {
    del.clear();
    root = 0 , nodecnt = 1;
    priority[0] = -1 << 30 , key[0] = -1<<30;
    Size[0] = 0;
  }
  int size()
  {
    return Size[root];
  }
  void update(int x)
  {
    Size[x] = Size[child[x][0]] + Size[child[x][1]] + cnt[x];
  }

  void rotate (int& x , int t)
  {
    int y = child[x][t];
    child[x][t] = child[y][t ^ 1];
    child[y][t ^ 1] = x;
    update(x) , update(y);
    x = y;
  }

  void __insert(int& x , int k)
  {
    if (x)
    {
      if (key[x] == k)
        x = x;//++ cnt[x];
      else
      {
        int t = key[x] < k;
        __insert(child[x][t] , k);
        if (priority[child[x][t]] > priority[x])
           rotate(x , t);
      }
    }
    else
    {
      if (del.size())
      {
        x = del.back();
        del.pop_back();
      }
      else x = nodecnt ++;
      key[x] = k;
      cnt[x] = 1;
      priority[x] = rand();
      child[x][0] = child[x][1] = 0;
    }
    update(x);
  }

  void __erase(int& x , int k)
  {
    if (!x) return;
    if (key[x] == k)
    {
     // if (cnt[x] > 1)
      //  -- cnt[x];
     // else
      {
        if (!child[x][0] && !child[x][1])
        {
          del.push_back(x);
          x = 0;
          return;
        }
        int t = priority[child[x][0]] < priority[child[x][1]];
        rotate(x , t);
        __erase(x , k);
      }
    }
    else
      __erase(child[x][key[x] < k] , k);
    update(x);
  }

  int __getKth(int& x , int k)
  {
    if (k <= Size[child[x][0]])
      return __getKth(child[x][0] , k);
    k -= Size[child[x][0]] + cnt[x];
    if (k <= 0)  return key[x];
    return __getKth(child[x][1] , k);
  }

  void insert(int x){
    __insert(root , x);}
  void erase(int x){
    __erase(root , x);}
  int getKth(int x){
    return __getKth(root , x);}
};

int n , m ;
Treap mx , mn;
void work()
{
  int i , x , y;
  scanf("%d",&n);
  mx.clear() , mn.clear();
  while (n --)
  {
    scanf("%d",&m);
    while (m --)
    {
      scanf("%d",&x);
      mx.insert(x);
      if (mx.size() > n + 3)
        mx.erase(mx.getKth(1));
      mn.insert(x) ;
      if (mn.size() > n + 3)
        mn.erase(mn.getKth(mn.size()));
    }
    if (mx.size() < 2 || mn.size() < 2)
      puts("-1 -1");
    else
    {
      x = mn.getKth(2);
      y = mx.getKth(mx.size() - 1);
      printf("%d %d\n" , x , y);
      mx.erase(x) , mn.erase(x);
      mx.erase(y) , mn.erase(y);
    }
  }
}

int main()
{
  int _; cin >> _;while (_--)
    work();
  return 0;
}


POJ2761 Feed the dogs
http://poj.org/problem?id=2761

区间互不包含这个条件非常强呀……区间排序之后从左往右扫一遍出解

int n , m , ans[N] , a[N];
struct query
{
  int l , r , k , num;
  bool operator < (const query& p) const{
    if(l == p.l)
      return r < p.r;
    return l < p.l;}
}q[N];
Treap T;

void work()
{
  int i , x , y , j;
  scanf("%d%d",&n,&m);
  for (i = 1 ; i <= n ; ++ i)
    scanf("%d",&a[i]);
  for (i = 0 ; i < m ; ++ i)
    scanf("%d%d%d",&q[i].l , &q[i].r , &q[i].k) , q[i].num = i;
  sort(q , q + m);

  x = 0 , y = 1;
  for (i = 0 ; i < m ; ++ i)
  {
    while (q[i].r > x)
      T.insert(a[++ x]);
    while (q[i].l > y)
      T.erase(a[y ++]);
    ans[q[i].num] = T.getKth(q[i].k);
  }
  for (i = 0 ; i < m ; ++ i)
    printf("%d\n" , ans[i]);
}

POJ2750 Potted Flower

http://poj.org/problem?id=2750

线段树,维护区间的权值和最大和最小的段

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <climits>
using namespace std;
#define N 100005
#define M 1000005
int n , m , a[N];

struct stree
{
  int sum;
  int lmax , rmax , smax;
  int lmin , rmin , smin;
}t[N << 1];
int id(int l , int r) {return l + r | l != r;}
#define MID int mid = (l + r) >> 1;
#define ID id(l , r)
#define Left l , mid
#define Right mid + 1 , r

void pushup(int l , int r)
{
  MID; int p = ID , LL = id(Left) , RR = id(Right);
  t[p].sum = t[LL].sum + t[RR].sum;
  t[p].lmax = max(t[LL].sum + t[RR].lmax , t[LL].lmax);
  t[p].rmax = max(t[RR].sum + t[LL].rmax , t[RR].rmax);
  t[p].smax = max(t[LL].rmax + t[RR].lmax , max(t[LL].smax , t[RR].smax));
  t[p].lmin = min(t[LL].sum + t[RR].lmin , t[LL].lmin);
  t[p].rmin = min(t[RR].sum + t[LL].rmin , t[RR].rmin);
  t[p].smin = min(t[LL].rmin + t[RR].lmin , min(t[LL].smin , t[RR].smin));
}

void update(int l , int r , int i , int x)
{
  if (l == r) {
    int p = ID; t[p].sum = x;
    t[p].lmax = t[p].rmax = t[p].smax = x;
    t[p].lmin = t[p].rmin = t[p].smin = x;
    return;}
  if (l == r) return; MID;
  if (i <= mid) update(Left , i , x);
  if (i > mid) update(Right , i , x);
  pushup(l , r);
}

void Build(int l , int r)
{
  if (l == r) {
    int p = ID; t[p].sum = a[l];
    t[p].lmax = t[p].rmax = t[p].smax = a[l];
    t[p].lmin = t[p].rmin = t[p].smin = a[l];
    return;}
  MID;Build(Left);Build(Right);pushup(l , r);
}


void work()
{
  int i , x , y , p , ans = 0;
  scanf("%d",&n);
  for (i = 1 ; i <= n ; ++ i)
    scanf("%d",&a[i]);
  Build(1 , n) , p = id(1 , n);
  scanf("%d",&m);
  while (m --)
  {
    scanf("%d%d",&x,&y);
    update(1 , n , x , y);
    ans = t[p].sum - t[p].smin;
    if (t[p].sum != t[p].smax)
      ans = max(t[p].smax , ans);
    printf("%d\n" , ans);
  }
}


int main()
{
  work();
  return 0;
}


BZOJ1503 [NOI2004]郁闷的出纳员

http://www.lydsy.com/JudgeOnline/problem.php?id=1503

简单的Treap操作

int n , Q;
Treap T;

void work()
{
  int i , x , y , ans = 0 , add = 0; char str[5];
  scanf("%d%d",&n,&Q);
  T.clear();
  while (n --)
  {
    scanf("%s" , str);
    if (*str == 'I')
    {
      scanf("%d",&x);
      if (x < Q);
      //  ++ ans;
      else T.insert(x - add);
    }
    if (*str == 'S')
    {
      scanf("%d",&x);
      add -= x;
      while (T.size() && (y = T.getKth(1)) + add - Q < 0)
        T.erase(y) , ++ ans;
    }
    if (*str == 'A')
    {
      scanf("%d",&x);
      add += x;
    }
    if (*str == 'F')
    {
      scanf("%d",&x);
      if (x > T.size())
        puts("-1");
      else printf("%d\n" , T.getKth(T.size() - x + 1) + add);
    }
  }
  printf("%d" , ans);
}

1208: [HNOI2004]宠物收养所

http://www.lydsy.com/JudgeOnline/problem.php?id=1208

multiset也能过

int n;
Treap pet[2];
void work()
{
  int i , x , k , l , r , ans = 0;
  pet[0].clear() , pet[1].clear();
  scanf("%d",&n);
  while (n --)
  {
    scanf("%d%d",&i,&x);
    if (!pet[i].size())
      pet[i ^ 1].insert(x);
    else
    {
      k = pet[i].Rank(x);
      if (k == 0)
      {
        r = pet[i].getKth(1);
        ans += abs(r - x) , ans %= 1000000;
        pet[i].erase(r);
        continue;
      }
      if (k == pet[i].size())
      {
        l = pet[i].getKth(pet[i].size());
        ans += abs(l - x) , ans %= 1000000;
        pet[i].erase(l);
        continue;
      }
      l = pet[i].getKth(k);
      if (l == x) continue;
      r = pet[i].getKth(k + 1);
      if (abs(l - x) <= abs(r - x))
        ans += abs(l - x) , ans %= 1000000 , pet[i].erase(l);
      else ans += abs(r - x) , ans %= 1000000 , pet[i].erase(r);
    }
  }
  printf("%d\n" , ans);
}

BZOJ1798: [Ahoi2009]Seq 维护序列seq

http://www.lydsy.com/JudgeOnline/problem.php?id=1798

线段树,注意标记下传的顺序

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <climits>
using namespace std;
#define N 100005
#define M 1000005
int n , m , a[N] , Q;
struct stree
{
  long long sum , multi , add;
}t[N << 1];
int id(int l , int r) {return l + r | l != r;}
#define MID int mid = (l + r) >> 1;
#define ID id(l , r)
#define Left l , mid
#define Right mid + 1 , r

void Multi(int Id , int x)
{
  t[Id].multi = t[Id].multi * x % Q;
  t[Id].sum = t[Id].sum * x % Q;
  t[Id].add = t[Id].add * x % Q;
}

void pushup(int l , int r)
{
  MID; int p = ID , LL = id(Left) , RR = id(Right);
  t[p].sum = (t[LL].sum + t[RR].sum) % Q;
}
void pushdown(int l , int r)
{
  MID; int p = ID , LL = id(Left) , RR = id(Right);
  if (t[p].multi != 1 % Q)
  {
    Multi(LL , t[p].multi);
    Multi(RR , t[p].multi);
    t[p].multi = 1 % Q;
  }
  if (t[p].add)
  {
    t[LL].sum = (t[LL].sum + t[p].add * (mid - l + 1)) % Q;
    t[LL].add = (t[LL].add + t[p].add) % Q;
    t[RR].sum = (t[RR].sum + t[p].add * (r - mid)) % Q;
    t[RR].add = (t[RR].add + t[p].add) % Q;
    t[p].add = 0;
  }
}

void update(int l , int r , int top , int bot , int q , int w)
{
  if (top <= l && r <= bot) {int p = ID;
    if (q == 1) Multi(ID , w);
    if (q == 2) t[p].add = (t[p].add + w) % Q , t[p].sum = (t[p].sum + w * (r - l + 1)) % Q;
    return;}MID;pushdown(l , r);
  if (top <= mid) update(Left , top , bot , q , w);
  if (bot > mid) update(Right , top , bot , q , w);
  pushup(l , r);
}

int Query(int l , int r , int top , int bot)
{
  if (top <= l && r <= bot) {return t[ID].sum;}MID;pushdown(l , r);int ans = 0;
  if (top <= mid) ans += Query(Left , top , bot);
  if (bot > mid) ans += Query(Right , top , bot);
  pushup(l , r); return ans % Q;
}

void Build(int l , int r)
{
  t[ID].multi = 1;
  if (l == r) {t[ID].sum = a[l];return;}
  MID;Build(Left);Build(Right);pushup(l , r);
}

void work()
{
  int i , x , y , c , ans = 0;
  scanf("%d%d",&n,&Q);
  for (i = 1 ; i <= n ; ++ i)
    scanf("%d",&a[i]);
  Build(1 , n);
  scanf("%d",&m);
  while (m --)
  {
    scanf("%d%d%d",&i,&x,&y);
    if (i < 3)
      scanf("%d" ,&c) , update(1 , n , x , y , i , c);
    else
      printf("%d\n" , Query(1 , n , x , y));
  }
}

int main()
{
  work();
  return 0;
}

ZJU2112 Dynamic Rankings

树套树,后来用树状数组套主席树写过但是MLE了,树状数组套主席树的空间消耗的确很大,相应却有优秀的时间效率

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <climits>
using namespace std;
#define N 50005
#define M 1000005
struct Treap
{
  int root ,  nodecnt , priority[M] , child[M][2];
  int key[M];
  int Size[M] , cnt[M];
  vector<int> del;

  void clear()
  {
    root = 0 , nodecnt = 1;
    priority[0] = INT_MIN;
    child[0][0] = child[0][1] = 0;
    key[0] = INT_MIN , cnt[0] = 0 , Size[0] = 0;
    del.clear();
  }

  void update(int x)
  {
    Size[x] = Size[child[x][0]] + Size[child[x][1]] + cnt[x];
  }

  void rotate (int& x , int t)
  {
    int y = child[x][t];
    child[x][t] = child[y][t ^ 1];
    child[y][t ^ 1] = x;
    update(x) , update(y);
    x = y;
  }

  void __insert(int& x , int k)
  {
    if (x)
    {
      if (key[x] == k)
        ++ cnt[x];
      else
      {
        int t = key[x] < k;
        __insert(child[x][t] , k);
        if (priority[child[x][t]] > priority[x])
           rotate(x , t);
      }
    }
    else
    {
      if (del.size())
      {
        x = del.back();
        del.pop_back();
      }
      else x = nodecnt ++;
      key[x] = k;
      cnt[x] = 1;
      priority[x] = rand() << 15 | rand();
      child[x][0] = child[x][1] = 0;
    }
    update(x);
  }

  void __erase(int& x , int k)
  {
    //if (!x) return;
    if (key[x] == k)
    {
      if (cnt[x] > 1)
        -- cnt[x];
      else
      {
        if (!child[x][0] && !child[x][1])
        {
          del.push_back(x);
          cnt[x] = 0 , x = 0;
          return;
        }
        int t = priority[child[x][0]] < priority[child[x][1]];
        rotate(x , t);
        __erase(x , k);
      }
    }
    else
      __erase(child[x][key[x] < k] , k);
    update(x);
  }
  int __Rank(int& x , int k)
  {
    if(!x) return 0;
    if (k < key[x])
      return __Rank(child[x][0] , k);
    int Rk = Size[child[x][0]] + cnt[x];
    if (k > key[x])
      Rk += __Rank(child[x][1] , k);
    return Rk;
  }
  int __getKth(int& x , int k)
  {
    if (k <= Size[child[x][0]])
      return __getKth(child[x][0] , k);
    k -= Size[child[x][0]] + cnt[x];
    if (k <= 0)  return key[x];
    return __getKth(child[x][1] , k);
  }
  /*void insert(int x){
    __insert(root , x);}
  void erase(int x){
    __erase(root , x);}
  int getKth(int x){
    return __getKth(root , x);}*/
};

int n , m , a[N] , ans;
Treap T;

int t[N << 1];
int id(int l , int r) {return l + r | l != r;}
#define MID int mid = (l + r) >> 1;
#define ID id(l , r)
#define Left l , mid
#define Right mid + 1 , r
void SInsert(int l , int r , int i , int x)
{
  T.__insert(t[ID] , x);
  if (l == r) return; MID;
  if (i <= mid) SInsert(Left , i , x);
  if (i > mid) SInsert(Right , i , x);
}
void SErase(int l , int r , int i , int x)
{
  T.__erase(t[ID] , x);
  if (l == r) return; MID;
  if (i <= mid) SErase(Left , i , x);
  if (i > mid) SErase(Right , i , x);
}
void SQuery(int l , int r , int top , int bot , int x)
{
  if (top <= l && r <= bot) {ans += T.__Rank(t[ID] , x); return;} MID;
  if (top <= mid) SQuery(Left , top , bot , x);
  if (bot > mid) SQuery(Right , top , bot , x);
}

void work()
{
  int i , x , y , l , r , mid , p; char s[5];
  memset(t , 0 , sizeof(t)) , T.clear();
  memset(a , 0 , sizeof(a));
  scanf("%d%d" ,&n,&m);
  for (i = 1 ; i <= n ; ++ i)
    scanf("%d",&a[i]) , SInsert(1 , n , i , a[i]);
  while (m --)
  {
    scanf("%s" , s);
    if (*s == 'C')
    {
      scanf("%d%d",&x,&y);
      SErase(1 , n , x , a[x]);
      a[x] = y;
      SInsert(1 , n , x , a[x]);
    }
    else
    {
      scanf("%d%d%d",&x,&y,&p);
      l = 0 , r = 1 << 30;
      while (l < r)
      {
        mid = (l + r) >> 1 , ans = 0;
        SQuery(1 , n , x , y , mid);
        if(ans < p) l = mid + 1; else r = mid;
      }
      printf("%d\n" , l);
    }
  }
}


int main()
{
  freopen("~input.txt","r",stdin);
  //srand((unsigned int)time(0));
  //while (scanf("%d%d",&n,&m) , n || m)
  int _; cin >> _;while (_--)
    work();
  return 0;
}


PKUcampus2013F Moles
http://poj.openjudge.cn/practice/1042/

线段树维护树的DFS序列,这样边权的变换和询问都可以转换到一个区间上的问题。

都有DFS序列了所以求LCA可以转成RMQ,但是还是偷懒直接倍增LCA了

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <stack>
using namespace std;
#define N 100005
#define M 1000005
int n , mcnt , pre[N] , f[N][17] , m , dis[N] , dep[N];
int cnt , begin[N] , end[N] , a[N] , ans;
struct edge
{
  int x , w , next;
}e[N << 1];

struct stree
{
  int w , f;
} t[N << 1];
int id(int l , int r) {return l + r | l != r;}
#define MID int mid = (l + r) >> 1;
#define ID id(l , r)
#define Left l , mid
#define Right mid + 1 , r
void pushup(int l , int r)
{
  MID;t[ID].w = max(t[id(Left)].w , t[id(Right)].w);
}
void pushdown(int l , int r)
{
  MID ;int p = ID , LL = id(Left) , RR = id(Right);
  if (t[p].f)
  {
    t[LL].w += t[p].f , t[LL].f += t[p].f ;
    t[RR].f += t[p].f , t[RR].w += t[p].f ;
    t[p].f = 0;
  }
}
void Build(int l , int r)
{
  if (l == r) {t[ID].w = a[l]; t[ID].f = 0 ;return;}
  MID;Build(Left);Build(Right);pushup(l , r);
}
void Query(int l , int r , int top , int bot)
{
  if (top <= l && r <= bot) {ans = max(ans , t[ID].w); return;}
  MID; pushdown(l , r);
  if (top <= mid) Query(Left , top , bot);
  if (bot > mid) Query(Right , top , bot);
  pushup(l , r);
}
void Update(int l , int r , int top , int bot , int x)
{
  if (top <= l && r <= bot) {t[ID].f += x , t[ID].w += x; return;}
  MID; pushdown(l , r);
  if (top <= mid) Update(Left , top , bot , x);
  if (bot > mid) Update(Right , top , bot , x);
  pushup(l , r);
}

void dfs(int x , int fa , int d , int w , int p)
{
  f[x][0] = fa , dis[x] = w , a[++ cnt] = d , begin[x] = cnt , dep[x] = p;
  for (int i = pre[x] ; ~i ; i = e[i].next)
    if (e[i].x != fa)
      dfs(e[i].x , x , d + e[i].w , e[i].w , p + 1);
  end[x] = cnt;
}
int LCA(int x , int y)
{
  int log , i ;
  if (dep[x] < dep[y]) swap(x , y); // x is deeper than y
  for (log = 1 ; (1 << log) <= dep[x] ; ++ log); -- log;
  for (i = log ; i >= 0 ; -- i)
    if (dep[x] - (1 << i) >= dep[y])
      x = f[x][i];
  if (x == y) return y; // y is ancstor of x
  for (i = log ; i >= 0 ; -- i)
    if (f[x][i] && f[x][i] != f[y][i])
      x = f[x][i] , y = f[y][i];
  return f[x][0];
}
void work()
{
  int i , j , x , y , z;
  scanf("%d",&n);
  memset(pre , -1 , sizeof(pre)) , mcnt = 0;
  memset(t , 0 , sizeof(t));
  memset(a , 0 , sizeof(a));
  memset(f , 0 , sizeof(f));

  for (i = 1 ; i < n ; ++ i)
  {
    scanf("%d%d%d",&x,&y,&z);
    e[mcnt] = (edge) {y , z , pre[x]} , pre[x] = mcnt ++;
    e[mcnt] = (edge) {x , z , pre[y]} , pre[y] = mcnt ++;
  }
  cnt = 0;
  dfs(1 , 0 , 0 , 0 , 0);
  for (j = 1 ; 1 << j < n ; ++ j)
    for (i = 1 ; i <= n ; ++ i)
      f[i][j] = f[f[i][j - 1]][j - 1];
  Build(1 , n);
  scanf("%d",&m);
  int pos = 1;
  while (m --)
  {
    scanf("%d",&i);
    if (i == 1)
    {
      scanf("%d",&x);
      y = LCA(x , pos);
      ans = -1 << 30; j = 0;
      Query(1 , n , begin[x] , begin[x]) , j += ans;
      ans = -1 << 30; Query(1 , n , begin[pos] , begin[pos]) , j += ans;
      ans = -1 << 30; Query(1 , n , begin[y] , begin[y]) , j -= ans << 1;
      printf("%d\n" , j);
      pos = x;
    }
    if (i == 2)
    {
      ans = -1 << 30;
      Query(1 , n , begin[pos] , begin[pos]);
      j = ans; ans = -1 << 30;
      Query(1 , n , begin[pos] , end[pos]);
      printf("%d\n" , ans - j);
    }
    if (i == 3)
    {
      scanf("%d%d%d",&x,&y,&z);
      if (dep[x] < dep[y]) swap(x , y);
      Update(1 , n , begin[x] , end[x] , z - dis[x]);
      dis[x] = z;
    }
  }
}

int main()
{
  int _; cin >> _;while (_--)
    work();
  return 0;
}

HDU2665 Kth number

http://acm.hdu.edu.cn/showproblem.php?pid=2665

看了主席树资料的以后YY写了一个,就拿这道题开刀了

维护的是一个离散化之后的权值“前缀和”的东西,其实就是可以理解为开了n棵线段树,但是只占了O(nlogn)的空间。

如果是带单点修改的话就需要用树状数组维护这个前缀和了,想起来也非常顺,但是写ZOJ那道题MLE。。

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <climits>
using namespace std;
#define N 100005
#define M 2000005
int id(int l , int r) {return l + r | l != r;}
#define MID int mid = (l + r) >> 1;
#define ID id(l , r)
#define Left l , mid
#define Right mid + 1 , r
#define LL child[p][0]
#define RR child[p][1]
struct Functional_stree
{
  int nodecnt;
  int root[N];
  int child[M][2] , sum[M];
  void clear()
  {
    nodecnt = 0;
    root[0] = child[0][0] = child[0][1] = sum[0] = 0;
  }
  int newnode()
  {
    child[++ nodecnt][0] = child[nodecnt][1] = 0;
    sum[nodecnt] = 0;
    return nodecnt;
  }
  void insert(int p , int q , int l , int r , int x)
  {
    if (l == r) {++ sum[p];return;} MID;
    if (x <= mid)
    {
      LL = newnode() , RR = child[q][1] , sum[LL] = sum[child[q][0]];
      insert(LL , child[q][0] , Left , x);
    }
    if (x > mid)
    {
      RR = newnode() , LL = child[q][0] , sum[RR] = sum[child[q][1]];
      insert(RR , child[q][1] , Right , x);
    }
    sum[p] = sum[LL] + sum[RR];
  }
  int Query(int p , int q , int l , int r , int k)
  {
    if (l == r) return l;MID;
    if (sum[LL] - sum[child[q][0]] >= k)
      return Query(LL , child[q][0] , Left , k);
    return Query(RR , child[q][1] , Right , k - sum[LL] + sum[child[q][0]]);
  }
};

Functional_stree t;
int n , a[N] , d[N] , m , Q;

void work()
{
  int i , x , y , k;
  scanf("%d%d",&m,&Q);
  t.clear();
  for (i = 1 ; i <= m ; ++ i)
    scanf("%d",&a[i]) , d[i] = a[i];
  sort(d + 1 , d + m + 1);
  n = unique(d + 1 , d + m + 1) - d - 1;
  for (i = 1 ; i <= m ; ++ i)
    a[i] = lower_bound(d + 1 , d + n + 1 , a[i]) - d;
  for (i = 1 ; i <= m ; ++ i)
  {
    t.root[i] = t.newnode();
    t.insert(t.root[i] , t.root[i - 1] , 1 , n , a[i]);
  }
  while (Q --)
  {
    scanf("%d%d%d",&x,&y,&k);
    printf("%d\n" , d[t.Query(t.root[y] , t.root[x - 1] , 1 , n , k)]);
  }
}

int main()
{
  int _; cin >> _;while (_--)
    work();
  return 0;
}

HDU4417 Super Mario

http://acm.hdu.edu.cn/showproblem.php?pid=4417

一段序列求某区间上有多少值<=某个值w

主席树好神好方便啊,就相当于求r这棵树-(l-1)这棵树有多少值<=w..

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <climits>
using namespace std;
#define N 100005
#define M 2000005
int id(int l , int r) {return l + r | l != r;}
#define MID int mid = (l + r) >> 1;
#define ID id(l , r)
#define Left l , mid
#define Right mid + 1 , r
#define LL child[p][0]
#define RR child[p][1]
#define QL child[q][0]
#define QR child[q][1]
struct Functional_stree
{
  int nodecnt;
  int root[N];
  int child[M][2] , sum[M];
  void clear()
  {
    nodecnt = 0;
    root[0] = child[0][0] = child[0][1] = sum[0] = 0;
  }
  int newnode()
  {
    child[++ nodecnt][0] = child[nodecnt][1] = 0;
    sum[nodecnt] = 0;
    return nodecnt;
  }
  void insert(int p , int q , int l , int r , int x)
  {
    if (l == r) {++ sum[p];return;} MID;
    if (x <= mid)
    {
      LL = newnode() , RR = QR , sum[LL] = sum[QL];
      insert(LL , QL , Left , x);
    }
    if (x > mid)
    {
      RR = newnode() , LL = QL , sum[RR] = sum[QR];
      insert(RR , QR , Right , x);
    }
    sum[p] = sum[LL] + sum[RR];
  }
  int Query(int p , int q , int l , int r , int k)
  {
    if (1 <= l && r <= k) return sum[p] - sum[q];MID;
    int ans = 0;
    if (1 <= mid) ans += Query(LL , QL , Left , k);
    if (k > mid) ans += Query(RR , QR , Right , k);
    return ans;
  }
};

Functional_stree t;
int n , a[N] , d[N] , m , Q , ca;

void work()
{
  int i , x , y , k;
  scanf("%d%d",&m,&Q);
  t.clear();
  for (i = 1 ; i <= m ; ++ i)
    scanf("%d",&a[i]) , d[i] = a[i];
  sort(d + 1 , d + m + 1);
  n = unique(d + 1 , d + m + 1) - d - 1;
  for (i = 1 ; i <= m ; ++ i)
    a[i] = lower_bound(d + 1 , d + n + 1 , a[i]) - d;
  for (i = 1 ; i <= m ; ++ i)
  {
    t.root[i] = t.newnode();
    t.insert(t.root[i] , t.root[i - 1] , 1 , n , a[i]);
  }
  printf("Case %d:\n" , ++ ca);
  while (Q --)
  {
    scanf("%d%d%d",&x,&y,&k) , ++ x , ++ y;
    k = upper_bound(d + 1 , d + n + 1 , k) - d - 1;
    if (!k) puts("0"); else
    printf("%d\n" , t.Query(t.root[y] , t.root[x - 1] , 1 , n , k));
  }
}

int main()
{
  int _; cin >> _;while (_--)
    work();
  return 0;
}

HDU3804 Query on a tree

http://acm.hdu.edu.cn/showproblem.php?pid=3804

同样用主席树,和上面那道题差不多

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <queue>
using namespace std;
#define N 100005
#define M 2000005
int id(int l , int r) {return l + r | l != r;}
#define MID int mid = (l + r) >> 1;
#define ID id(l , r)
#define Left l , mid
#define Right mid + 1 , r
#define LL child[p][0]
#define RR child[p][1]
#define QL child[q][0]
#define QR child[q][1]
struct Functional_stree
{
  int nodecnt;
  int root[N];
  int child[M][2] , sum[M];
  void clear()
  {
    nodecnt = 0;
    root[0] = child[0][0] = child[0][1] = sum[0] = 0;
  }
  int newnode()
  {
    child[++ nodecnt][0] = child[nodecnt][1] = 0;
    sum[nodecnt] = 0;
    return nodecnt;
  }
  void insert(int p , int q , int l , int r , int x)
  {
    if (l == r) {++ sum[p];return;} MID;
    if (x <= mid)
    {
      LL = newnode() , RR = QR , sum[LL] = sum[QL];
      insert(LL , QL , Left , x);
    }
    if (x > mid)
    {
      RR = newnode() , LL = QL , sum[RR] = sum[QR];
      insert(RR , QR , Right , x);
    }
    sum[p] = sum[LL] + sum[RR];
  }
  int rank(int p , int l , int r , int k)
  {
    if (1 <= l && r <= k) return sum[p]; MID;
    int ans = 0;
    if (1 <= mid) ans += rank(LL , Left , k);
    if (k > mid) ans += rank(RR , Right , k);
    return ans;
  }
  int Query(int p , int l , int r , int k)
  {
    if (l == r) return l; MID;
    if (sum[LL] >= k) return Query(LL , Left , k);
    return Query(RR , Right , k - sum[LL]);
  }
};

Functional_stree t;
int n , d[N] , m , Q;
struct edge
{
  int x , w , next;
}e[N << 1];
int pre[N] , mcnt;
bool f[N];
void BFS()
{
  int i , x , y , z; memset(f , 0 , sizeof(f));
  queue<int> q; q.push(1) , f[1] = 1;
  while (!q.empty())
  {
    x = q.front() , q.pop();
    for (i = pre[x] ; ~i ; i = e[i].next) if (!f[y = e[i].x])
    {
      z = lower_bound(d + 1 , d + n + 1 , e[i].w) - d;
      t.root[y] = t.newnode();
      t.insert(t.root[y] , t.root[x] , 1 , n , z);
      f[y] = 1 , q.push(y);
    }
  }
}
void work()
{
  int i , x , y , z , k;
  scanf("%d",&n) , memset(d , 0 , sizeof(d)) , d[0] = -1;
  t.clear() , memset(pre , -1 , sizeof(pre)) , mcnt = 0;
  for (i = 1 ; i < n ; ++ i)
  {
    scanf("%d%d%d",&x,&y,&z) , d[i] = z;
    e[mcnt] = (edge) {y , z , pre[x]} , pre[x] = mcnt ++;
    e[mcnt] = (edge) {x , z , pre[y]} , pre[y] = mcnt ++;
  }
  sort(d + 1 , d + n) , n = unique(d + 1 , d + n) - d - 1;
  t.root[1] = t.newnode() , BFS();
  scanf("%d",&Q);
  while (Q --)
  {
    scanf("%d%d",&x ,&k); if (x == 1) {puts("-1");continue;}
    k = upper_bound(d + 1 , d + n + 1 , k) - d - 1;
    if (!k) {puts("-1");continue;}k = t.rank(t.root[x] , 1 , n , k);if (!k) {puts("-1");continue;}
    printf("%d\n" , d[t.Query(t.root[x] , 1 , n , k)]);
  }
}

int main()
{
  int _; cin >> _;while (_--)
    work();
  return 0;
}



POJ 3580 SuperMemo

http://poj.org/problem?id=3580

维护一段序列。。用可以split和merge的Treap写的,昨天至少调了3个小时。。

写完成就感爆棚啊。。

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <climits>
using namespace std;
#define N 100005
#define M 2000005


struct Segment_Treap
{
  int nodecnt , root;
  //int root[N];
  int key[M] ;
  int priority[M] , add[M] , sum[M] , mn[M];
  int l[M] , r[M];
  bool rev[M];
  vector<int> del;
  void clear()
  {
    nodecnt = 0 , root = 0;
    del.clear() , priority[0] = -1 << 30;
    //root[0] = child[0][0] = child[0][1] = key[0] = 0;
  }
  void pushdown(int x)
  {
    if (rev[x])
    {
      if(l[x]) swap(l[l[x]] , r[l[x]]) , rev[l[x]] ^= 1;
      if(r[x]) swap(l[r[x]] , r[r[x]]) , rev[r[x]] ^= 1;
      rev[x] ^= 1;
    }
    if (add[x])
    {
      if(l[x]) mn[l[x]] += add[x] , key[l[x]] += add[x] , add[l[x]] += add[x];
      if(r[x]) mn[r[x]] += add[x] , key[r[x]] += add[x] , add[r[x]] += add[x];
      add[x] = 0;
    }
  }
  void pushup(int x)
  {
    mn[x] = key[x] , sum[x] = 1;
    if (l[x]) mn[x] = min(mn[x] , mn[l[x]]) , sum[x] += sum[l[x]];
    if (r[x]) mn[x] = min(mn[x] , mn[r[x]]) , sum[x] += sum[r[x]];
  }
  void __insert(int& x , int i , int k)
  {
    if (x)
    {
      pushdown(x);
      if (sum[l[x]] + 1 >= i)
      {
        __insert(l[x] , i , k);
        int y = l[x];
        if (priority[y] < priority[x])
        {
          pushdown(y);
          l[x] = r[y] , r[y] = x , x = y;
          pushup(r[x]);
        }
      }
      else
      {
        __insert(r[x] , i - sum[l[x]] - 1 , k);
        int y = r[x];
        if (priority[y] < priority[x])
        {
          pushdown(y);
          r[x] = l[y] , l[y] = x , x = y;
          pushup(l[x]);
        }
      }
    }
    else
    {
      if (del.size())
        x = del.back() , del.pop_back();
      else x = ++ nodecnt;
      mn[x] = key[x] = k , sum[x] = 1;
      add[x] = rev[x] = 0;
      priority[x] = rand() << 15 | rand();
      l[x] = r[x] = 0;
    }
    pushup(x);
  }
  void insert(int i , int k) {__insert(root , i , k);}

  void merge(int& p , int x , int y)
  {
    if (!x || !y) p = x | y;
    else if (priority[x] < priority[y])
      pushdown(x) , merge(r[x] , r[x] , y) , pushup(x) , p = x;
    else pushdown(y) , merge(l[y] , x , l[y]) , pushup(y) , p = y;
  }
  void __erase(int& x , int i)
  {
    pushdown(x);
    if (sum[l[x]] + 1 == i)
    {
      del.push_back(x);
      merge(x , l[x] , r[x]);
    }else
    if (sum[l[x]] + 1 > i)
      __erase(l[x] , i) , pushup(x);
    else if (sum[l[x]] + 1 < i)
      __erase(r[x] , i - sum[l[x]] - 1) , pushup(x);

  }
  void erase(int i) {__erase(root , i);}

  void split(int p , int& x , int& y , int i)
  {
    if (!i) {x = 0 ; y = p;return;}
    if (i == sum[p]) {x = p ; y = 0;return;}
    pushdown(p);
    if (sum[l[p]] >= i)
    {
      y = p;
      split(l[p] , x , l[y] , i);
      pushup(y);
    }
    else
    {
      x = p;
      split(r[p] , r[x] , y , i - sum[l[p]] - 1);
      pushup(x);
    }
  }
  int __query(int x , int a , int b)
  {
    if (a == 1 && b == sum[x]) return mn[x];
    pushdown(x);
    int u = sum[l[x]] + 1;
    int p = (a <= u && u <= b ? key[x] : 1 << 30);
    if (a < u) p = min(p , __query(l[x] , a , b >= u ? u - 1 : b));
    if (b > u) p = min(p , __query(r[x] , a <= u ? 1 : a - u , b - u));
    return p;
  }
  int query(int a , int b) {return __query(root , a , b);}

  int Reverse(int a , int b)
  {
    int x , y , z;
    split(root , x , y , a - 1);
    split(y , y , z , b - a + 1);
    rev[y] ^= 1 , swap(l[y] , r[y]);
    merge(x , x , y);
    merge(root , x , z);
  }
  int Add(int a , int b , int c)
  {
    int x , y , z;
    split(root , x , y , a - 1);
    split(y , y , z , b - a + 1);
    key[y] += c , mn[y] += c , add[y] += c;
    merge(x , x , y);
    merge(root , x , z);
  }
  int Revolve(int a , int b , int c)
  {
    int w , x , y , z;
	split(root , w , x , a - 1);
	split(x , x , y , b - a + 1);
	split(y , y , z , c - b);
	merge(w , w , y);
	merge(w , w , x);
	merge(root , w , z);
  }
};
Segment_Treap T;

void work()
{
  int n , i , x , y , z , m; char str[50];
  scanf("%d",&n);T.clear();
  for (i = 1 ; i <= n ; ++ i)
    scanf("%d",&x) , T.insert(i , x);
  scanf("%d",&m);
  while (m --)
  {
    scanf("%s" , str);
    if (*str == 'A')
    {
      scanf("%d%d%d",&x,&y,&z);
      T.Add(x , y , z);
    }else
    if (*str == 'I')
    {
      scanf("%d%d",&x,&y);
      T.insert(x + 1 , y);
    }else
    if (*str == 'D')
    {
      scanf("%d",&x);
      T.erase(x);
    }else
    if (*str == 'M')
    {
      scanf("%d%d",&x,&y);
      printf("%d\n" , T.query(x , y));
    }else
    if (*(str + 3) == 'E')
    {
      scanf("%d%d",&x,&y);
      T.Reverse(x , y);
    }else
    {
      scanf("%d%d%d",&x,&y,&z);
      z = (z % (y - x + 1) + y - x + 1) % (y - x + 1);
      if (z) T.Revolve(x , y - z , y);
    }
  }
}

int main()
{
  work();
  return 0;
}


BZOJ1251 序列终结者
http://www.lydsy.com/JudgeOnline/problem.php?id=1251

完全就是套上面那道题啦。。

代码就不贴了


BZOJ1269  [AHOI2006]文本编辑器editor

http://www.lydsy.com/JudgeOnline/problem.php?id=1269

题目都差不多,只是发现带垃圾回收的版本比不带的快好多,只要空间开足够就好。

Segment_Treap T;

void work()
{
  int n , i , x , y , z , m; char str[50] , c;
  scanf("%d",&m);
  int pos = 0;
  while (m --)
  {
    scanf("%s" , str);
    if (*str == 'I')
    {
      scanf("%d",&n);getchar(); x = 0;
      for (i = 1 ; i <= n ; ++ i)
      {
        c = getchar();
        T.__insert(x , i , c);
      }
      T.split(T.root , y , z , pos);
      T.merge(y , y , x);
      T.merge(T.root , y , z);
    }
    if (*str == 'M')
      scanf("%d",&pos);
    if (*str == 'D')
    {
      scanf("%d",&x);
      T.split(T.root , y , z , pos);
      T.split(z , i , z , x);
      T.merge(T.root , y , z);
    }
    if (*str == 'R')
    {
      scanf("%d",&x);
      T.Reverse(pos + 1 , pos + x);
    }
    if (*str == 'P')
      -- pos;
    if (*str == 'N')
      ++ pos;
    if (*str == 'G')
      printf("%c\n" , T.query(pos + 1));
  }
}


BZOJ1507: [NOI2003]Editor

http://www.lydsy.com/JudgeOnline/problem.php?id=1507

样例第二条Move 16是错的,应该是Move 15

然后调了半天……然后就没什么了

Segment_Treap T;


void work()
{
  int n , i , x , y , z , m; char str[50] , c;
  //T.clear();
  scanf("%d",&m);
  int pos = 0;
  while (m --)
  {
    scanf("%s" , str);
    if (*str == 'I')
    {
      scanf("%d",&n);getchar(); x = 0;
      for (i = 1 ; i <= n ; ++ i)
      {
        c = getchar(); if (c == '\n' || c == '\r') {-- i;continue;}
        T.__insert(x , i , c);
      }
      T.split(T.root , y , z , pos);
      T.merge(y , y , x);
      T.merge(T.root , y , z);
    }
    if (*str == 'M')
      scanf("%d",&pos);
    if (*str == 'D')
    {
      scanf("%d",&x);
      T.split(T.root , y , z , pos);
      T.split(z , i , z , x);
      //T.__delete(i);
      T.merge(T.root , y , z);
    }
    if (*str == 'P')
      -- pos;
    if (*str == 'N')
      ++ pos;
    if (*str == 'G')
    {
      scanf("%d",&x);
      T.split(T.root , y , z , pos);
      T.split(z , i , z , x);
      T.__puts(i);puts("");
      T.merge(z , i , z);
      T.merge(T.root , y , z);
    }
  }
}

BZOJ1500: [NOI2005]维修数列

http://www.lydsy.com/JudgeOnline/problem.php?id=1500

本机挺快AC但是OJ疯狂TLE。。有什么强大的数据?

好吧发现splay速度是我这个Treap的3倍以上QAQ

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <cstdlib>
#include <ctime>
using namespace std;
#define N 100005
#define M 500005

struct Segment_Treap
{
  int nodecnt , root;
  int key[M] ;
  unsigned int priority[M] ;
  int sum[M] , cnt[M];
  int l[M] , r[M];
  int lm[M] , rm[M] , sm[M];
  int del , sz[M];
  bool rev[M] , same[M];
  void pushdown(int x)
  {
    if (rev[x])
    {
      if(l[x]) swap(l[l[x]] , r[l[x]]) , rev[l[x]] ^= 1 , swap(lm[l[x]] , rm[l[x]]);
      if(r[x]) swap(l[r[x]] , r[r[x]]) , rev[r[x]] ^= 1 , swap(lm[r[x]] , rm[r[x]]);
      rev[x] ^= 1;
    }
    if (same[x])
    {
      if(l[x]) same[l[x]] = 1 , key[l[x]] = key[x] , cnt[l[x]] = key[x] * sum[l[x]] ,
      lm[l[x]] = rm[l[x]] = sm[l[x]] = max(key[x] , cnt[l[x]]);
      if(r[x]) same[r[x]] = 1 , key[r[x]] = key[x] , cnt[r[x]] = key[x] * sum[r[x]] ,
      lm[r[x]] = rm[r[x]] = sm[r[x]] = max(key[x] , cnt[r[x]]);
      same[x] = 0;
    }
  }
  void pushup(int x)
  {
    cnt[x] = key[x] , sum[x] = 1;
    lm[x] = cnt[l[x]] + max(key[x] , 0), rm[x] = cnt[r[x]] + max(key[x] , 0) , sm[x] = max(lm[r[x]] , 0) + key[x] + max(rm[l[x]] , 0);
    if(l[x]) lm[x] = max(lm[x] , lm[l[x]]) , rm[x] = max(rm[x] , cnt[r[x]] + key[x] + rm[l[x]]) ,
             sm[x] = max(sm[x] , sm[l[x]]) , cnt[x] += cnt[l[x]] , sum[x] += sum[l[x]];
    if(r[x]) rm[x] = max(rm[x] , rm[r[x]]) , lm[x] = max(lm[x] , cnt[l[x]] + key[x] + lm[r[x]]) ,
             sm[x] = max(sm[x] , sm[r[x]]) , cnt[x] += cnt[r[x]] , sum[x] += sum[r[x]];
  }
  void __insert(int& x , int i , int k)
  {
    if (x)
    {
      pushdown(x);
      if (sum[l[x]] + 1 >= i)
      {
        __insert(l[x] , i , k);
        int y = l[x];
        if (priority[y] < priority[x])
        {
          pushdown(y);
          l[x] = r[y] , r[y] = x , x = y;
          pushup(r[x]);
        }
      }
      else
      {
        __insert(r[x] , i - sum[l[x]] - 1 , k);
        int y = r[x];
        if (priority[y] < priority[x])
        {
          pushdown(y);
          r[x] = l[y] , l[y] = x , x = y;
          pushup(l[x]);
        }
      }
    }
    else
    {
      if (del) x = sz[del --];else x = ++ nodecnt;
      cnt[x] = key[x] = k , sum[x] = 1;
      lm[x] = rm[x] = sm[x] = cnt[x];
      same[x] = rev[x] = 0;
      priority[x] = rand();
      l[x] = r[x] = 0;
    }
    pushup(x);
  }
  void merge(int& p , int x , int y)
  {
    if (!x || !y) p = x | y;
    else if (priority[x] < priority[y])
      pushdown(x) , merge(r[x] , r[x] , y) , pushup(x) , p = x;
    else pushdown(y) , merge(l[y] , x , l[y]) , pushup(y) , p = y;
  }

  void split(int p , int& x , int& y , int i)
  {
    if (!i) {x = 0 ; y = p;return;}
    if (i == sum[p]) {x = p ; y = 0;return;}
    pushdown(p);
    if (sum[l[p]] >= i)
    {
      y = p;
      split(l[p] , x , l[y] , i);
      pushup(y);
    }
    else
    {
      x = p;
      split(r[p] , r[x] , y , i - sum[l[p]] - 1);
      pushup(x);
    }
  }
  void bye(int x)
  {
    if(l[x]) bye(l[x]); sz[++ del] = x; if(r[x]) bye(r[x]);
  }
  int __query(int x , int a , int b)
  {
    if (a == 1 && b == sum[x]) return cnt[x];
    pushdown(x);
    int u = sum[l[x]] + 1;
    int p = (a <= u && u <= b ? key[x] : 0);
    if (a < u) p += __query(l[x] , a , b >= u ? u - 1 : b);
    if (b > u) p += __query(r[x] , a <= u ? 1 : a - u , b - u);
    return p;
  }
};
Segment_Treap T;
int Get() {
    char c=getchar(); int ret=0;
    while ((c!='-')&&((c<'0')||(c>'9'))) c=getchar();
    if (c=='-') return -Get();
    while ((c>='0')&&(c<='9')) ret=ret*10+c-'0',c=getchar();
    return ret;
}
void work()
{
  int n , i , j , x , y , z , m; char str[20];
  n = Get() , m = Get();
  for (i = 1 ; i <= n ; ++ i)
    x = Get() , T.__insert(T.root , i , x);
  while (m --)
  {
    scanf("%s" , str);
    if (*str == 'I')
    {
      y = Get() ; n = Get(); x = 0;
      for (i = 1 ; i <= n ; ++ i)
        z = Get() , T.__insert(x , i , z);
      T.split(T.root , j , z , y);
      T.merge(j , j , x);
      T.merge(T.root , j , z);
      continue;
    }
    if (*str == 'D')
    {
      i = Get() ; j = Get();
      T.split(T.root , x , y , i - 1);
      T.split(y , y , z , j); T.bye(y);
      T.merge(T.root , x , z);continue;
    }
    if (*(str + 2) == 'K')
    {
      i = Get() ; j = Get(); n = Get();
      T.split(T.root , x , y , i - 1);
      T.split(y , y , z , j);
      T.key[y] = n , T.same[y] = 1 , T.cnt[y] = T.sum[y] * n;
      T.lm[y] = T.rm[y] = T.sm[y] = max(T.cnt[y] , n);
      T.merge(y , y , z);
      T.merge(T.root , x , y);continue;
    }
    if (*str == 'R')
    {
      i = Get() ; j = Get();
      T.split(T.root , x , y , i - 1);
      T.split(y , y , z , j);
      T.rev[y] ^= 1 , swap(T.l[y] , T.r[y]) , swap(T.lm[y] , T.rm[y]);
      T.merge(y , y , z);
      T.merge(T.root , x , y);continue;
    }
    if (*str  == 'G')
    {
      i = Get() ; j = Get();
      printf("%d\n" , T.__query(T.root , i , i + j - 1));continue;
    }
    if (*(str + 2) == 'X')
      printf("%d\n" , T.sm[T.root]);
  }
}


int main()
{
  freopen("sequence.in","r",stdin);
  freopen("sequence.out","w",stdout);
  work();
  return 0;
}

Splay版,因为一个白痴问题调了很久……

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

#define N 500005
int a[N];
struct splay_tree
{
  int root , nodecnt , c[N][2] , size[N] , par[N] , type[N] , stack[N];
  int key[N] , sum[N] , lm[N] , rm[N] , sm[N] , same[N];
  bool rev[N];
  int rub[N] , rs;
  void clear()
  {
    root = 0 , size[0] = 0;
    c[0][0] = c[0][1] = par[0] = 0;
    rev[0] = 0 , same[0] = 1 << 30;
    nodecnt = 0;
  }
  int malloc(int k)
  {
    int x;
    if (rs) x = rub[rs --]; else x = ++ nodecnt;
    sum[x] = key[x] = k , size[x] = 1 , type[x] = -1;
    lm[x] = rm[x] = sm[x] = key[x];
    same[x] = 1 << 30 , rev[x] = 0;
    c[x][0] = c[x][1] = par[x] =0;
    return x;
  }
  void pushdown(int x)
  {
    if (rev[x])
    {
      swap(lm[x] , rm[x]) , swap(c[x][0] , c[x][1]);
      if(c[x][0]) rev[c[x][0]] ^= 1 , type[c[x][0]] = 0;
      if(c[x][1]) rev[c[x][1]] ^= 1 , type[c[x][1]] = 1;
      rev[x] ^= 1;
    }
    if (same[x] != 1 << 30)
    {
      key[x] = same[x] , sum[x] = key[x] * size[x];
      lm[x] = rm[x] = sm[x] = max(key[x] , sum[x]);
      if(c[x][0]) same[c[x][0]] = same[x];
      if(c[x][1]) same[c[x][1]] = same[x];
      same[x] = 1 << 30;
    }
  }
  void pushup(int x)
  {
    if (!x) return; pushdown(x);  pushdown(c[x][0]);  pushdown(c[x][1]);
    sum[x] = key[x] , size[x] = 1;
    lm[x] = sum[c[x][0]] + max(key[x] , 0), rm[x] = sum[c[x][1]] + max(key[x] , 0) , sm[x] = max(lm[c[x][1]] , 0) + key[x] + max(rm[c[x][0]] , 0);
    if(c[x][0]) lm[x] = max(lm[x] , lm[c[x][0]]) , rm[x] = max(rm[x] , sum[c[x][1]] + key[x] + rm[c[x][0]]) ,
             sm[x] = max(sm[x] , sm[c[x][0]]) , sum[x] += sum[c[x][0]] , size[x] += size[c[x][0]];
    if(c[x][1]) rm[x] = max(rm[x] , rm[c[x][1]]) , lm[x] = max(lm[x] , sum[c[x][0]] + key[x] + lm[c[x][1]]) ,
             sm[x] = max(sm[x] , sm[c[x][1]]) , sum[x] += sum[c[x][1]] , size[x] += size[c[x][1]];

  }
  void rotate (int x)
  {
    int t = type[x] , y = par[x] , z = c[x][t ^ 1];
    type[x] = type[y] , par[x] = par[y];
    if (~type[x]) c[par[x]][type[x]] = x;
    type[y] = t ^ 1 , par[y] = x , c[x][t ^ 1] = y;
    if (x) type[z] = t , par[z] = y;
    c[y][t] = z , pushup(y);
  }
  void splay(int x)
  {
    int cnt = 0 , i; stack[++ cnt] = x;
    for (i = x ; ~type[i] ; i = par[i])
      stack[++ cnt] = par[i];
    for (i = cnt ; i > 0 ; -- i) pushdown(stack[i]);
    while (~type[x])
    {
      int y = par[x];
      if (type[x] == type[y])rotate(y) ;else rotate(x);
      if (!~type[x]) break;
      rotate(x);
    }
    pushup(x);
  }
  int getKth(int x , int k)
  {
    while (1)
    {
      pushdown(x);
      if (size[c[x][0]] + 1 == k) break;
      if (size[c[x][0]] + 1 > k)
        x = c[x][0];
      else
        k -= size[c[x][0]] + 1 , x = c[x][1];
    }
    return x;
  }
  void split(int p , int& x , int& y , int a)
  {
    if (a == size[p]) {x = p , y = 0;return;}
    y = getKth(p , a + 1) , splay(y);
    x = c[y][0] , type[x] = -1 , c[y][0] = 0 , par[x] = 0;
    pushup(y);
  }
  void merge(int& p , int x ,int y)
  {
    if (!x || !y) {p = x | y ; return;} pushdown(x);
    p = getKth(x , size[x]) , splay(p) , c[p][1] = y;
    type[y] = 1 , par[y] = p , pushup(p);
  }

  int Build(int l , int r)
  {
    if (l > r) return 0;
    int m = (l + r) >> 1;
    int x = malloc(a[m]);
    c[x][0] = Build(l , m - 1) ;if(c[x][0]) type[c[x][0]] = 0 , par[c[x][0]] = x;
    c[x][1] = Build(m + 1 , r) ;if(c[x][1]) type[c[x][1]] = 1 , par[c[x][1]] = x;
    pushup(x);return x;
  }
  void del(int x)
  {
    if (c[x][0]) del(c[x][0]);
    rub[++ rs] = x;
    if (c[x][1]) del(c[x][1]);
  }
  void print(int x)
  {
    pushdown(x);
    if (c[x][0]) print(c[x][0]);
    printf("%d ", key[x]);
    if (c[x][1]) print(c[x][1]);
  }
};

splay_tree T;

int main()
{
  freopen("sequence.in","r",stdin);
  freopen("sequence.out","w",stdout);
  int n , m , x , y , z , l , r , i; char str[20];
  T.clear(); scanf("%d%d",&n,&m);
  for (i = 1 ; i <= n ; ++ i)
    scanf("%d",&a[i]);
  T.root = T.Build(1 , n);
  while (m --)
  {
    scanf("%s" , str);
    if (*(str + 2) == 'X')
      printf("%d\n" , T.sm[T.root]);
    else if (*str == 'I')
    {
      scanf("%d%d",&l,&n);
      T.split(T.root , x , y , l);
      for (i = 1 ; i <= n ; ++ i)
        scanf("%d",&a[i]);
      z = T.Build(1 , n);
      T.merge(x , x , z);
      T.merge(T.root , x , y);
    }
    else
    {
      scanf("%d%d",&l,&r);
      T.split(T.root , x , y , l - 1);
      T.split(y , y , z , r);
      if (*str == 'G') printf("%d\n" , T.sum[y]);
      if (*str == 'D') T.del(y) , T.merge(T.root , x , z);
      if (*str == 'M') scanf("%d",&T.same[y]);
      if (*str == 'R') T.rev[y] ^= 1;
      if (*str != 'D') T.merge(y , y , z) , T.merge(T.root , x , y);
    }
  }
  return 0;
}



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值