【BZOJ1125】【POI2008】Poc 原名:Train hash+離散化+平衡樹(splay)
連結:
#include <stdio.h>
int main()
{
puts("轉載請註明出處[vmurder]謝謝");
puts("網址:blog.csdn.net/vmurder/article/details/45739895");
}
題解:
首先我們發現對於每個串,我們把它hash一下,然後建一棵平衡樹來支援“插入”、“刪除”、“下傳標記”這三種操作就可以記錄並更新一個點的答案了。
然後每個串的串長都較小,修改字元時可以暴力重新hash。
注意:
- 一對互相交換字元的字串要先一起刪掉再一起往平衡樹里加。
- 可能是同一個串的倆字元交換,此時不能從平衡樹中刪兩遍。
- 德萊文初始攻速接斧頭之間只能再A一下(霧,呃覺得兩條太單薄
程式碼:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 305000
#define P 1050
#define ls son[x][0]
#define rs son[x][1]
#define is(x) (son[fa[x]][1]==x)
#define base 233
#define end(i) (n+(i<<1))
using namespace std;
struct GANK
{
unsigned long long h;
int v,f,k;
void read(unsigned _h,int _v,int _f)
{h=_h,v=_v,f=_f;}
}gank[N];
bool cmph(const GANK &A,const GANK &B){return A.h<B.h;}
bool cmpf(const GANK &A,const GANK &B){return A.f<B.f;}
int ans[N],n,m,p,cnt;
struct SPT
{
int son[N][2],fa[N],root[N],belong[N],num[N],kda[N];
void pushdown(int x)
{
ans[x]=max(ans[x],kda[x]);
kda[ls]=max(kda[ls],kda[x]);
kda[rs]=max(kda[rs],kda[x]);
kda[x]=0;
}
void link(int x,int y,int d){son[y][d]=x,fa[x]=y;}
void rotate(int x)
{
int y,z,i=is(x),t;
y=fa[x],z=fa[y],t=son[x][!i];
pushdown(y),pushdown(x);
link(x,z,is(y)),link(y,x,!i),link(t,y,i);
son[0][0]=son[0][1]=fa[0]=0;
}
void splay(int rt,int x,int d=0)
{
int y,z;
while(fa[x]!=d)
{
y=fa[x],z=fa[y];
if(z==d)rotate(x);
else rotate(is(x)==is(y)?y:x),rotate(x);
}
if(!d)root[rt]=x;
}
int succ(int rt,int x)
{
splay(rt,x);
for(x=rs;ls;x=ls);
return x;
}
void insert(int rt,int v)
{
int x=root[rt];
if(!rs)x=ls;
int suc=succ(rt,x);
splay(rt,suc,x);
pushdown(x),pushdown(suc);
link(v,suc,0),num[rt]++;
splay(rt,v),kda[v]=num[rt],belong[v]=rt;
}
void remove(int rt,int x)
{
splay(rt,succ(rt,x));
splay(rt,x,root[rt]);
pushdown(root[rt]);
pushdown(x);
link(ls,root[rt],0);
ls=rs=fa[x]=0,num[rt]--;
}
void add(int i){insert(gank[i].k,gank[i].v);}
void rem(int i){remove(belong[gank[i].v],gank[i].v);}
void init()
{
int i,j,k;
for(i=1;i<=cnt;i++)
{
int a=end(i)-1,b=end(i);
link(b,root[i]=a,1);
}
for(i=1;i<=n;i++)add(i);
}
}spt;
char s[P][P];
unsigned long long baser;
int main()
{
int i,j,k;
int a,b,c,d;
scanf("%d%d%d",&n,&m,&p);
for(i=1;i<=n;i++)
{
scanf("%s",s[i]+1);
for(baser=0,j=1;j<=m;j++)
baser=baser*base+s[i][j];
gank[i].read(baser,i,0);
}
for(i=1;i<=p;i++)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
if(s[a][b]==s[c][d])
{
i--,p--;
continue;
}
swap(s[a][b],s[c][d]);
for(baser=0,j=1;j<=m;j++)
baser=baser*base+s[a][j];
gank[n+i*2-1].read(baser,a,i);
for(baser=0,j=1;j<=m;j++)
baser=baser*base+s[c][j];
gank[n+i * 2].read(baser,c,i);
}
sort(gank+1,gank+n+p*2+1,cmph);
gank[0].h=gank[1].h^1;
for(i=1;i<n+p*2+1;i++)
{
if(gank[i].h!=gank[i-1].h)cnt++;
gank[i].k=cnt;
}
sort(gank+1,gank+n+p*2+1,cmpf);
spt.init();
for(i=1;i<=p;i++)
{
b=n+i*2,a=b-1;
if(gank[a].v==gank[b].v)
spt.rem(a),spt.add(a);
else {
spt.rem(a),spt.rem(b);
spt.add(a),spt.add(b);
}
}
for(i=1;i<=n;i++)spt.remove(spt.belong[i],i);
for(i=1;i<=n;i++)printf("%d\n",ans[i]);
return 0;
}
相關文章
- 普通平衡樹學習筆記之Splay演算法筆記演算法
- [學習筆記] Splay & Treap 平衡樹 - 資料結構筆記資料結構
- 【dp+離散化+線段樹優化】Paint優化AI
- hdu4325 樹狀陣列+離散化陣列
- 離散化
- [POI2008] POC-Trains 題解AI
- POJ 2528 Mayor's posters (線段樹 區間更新+離散化)
- POJ 2582 Mayor's posters 線段樹入門題+離散化
- POJ 2528 Mayor's posters (線段樹區間更新 + 離散化)
- HDU 5862 Counting Intersections(樹狀陣列+掃描線+離散化)陣列
- HDU4991 Ordered Subsequence (dp+樹狀陣列+離散化)陣列
- hdu 3973 字串hash+線段樹字串
- 伸展樹(Splay)學習筆記筆記
- 平衡樹
- 【離散優化】覆蓋問題優化
- 二維座標離散化模板
- 連續特徵離散化和歸一化特徵
- LeetCode 493. 翻轉對(歸併排序 || 離散化+樹狀陣列)LeetCode排序陣列
- 平衡查詢樹
- 離散請求
- 平衡二叉樹(AVL樹)和 二叉排序樹轉化為平衡二叉樹 及C語言實現二叉樹排序C語言
- Leetcode 327. 區間和的個數 (字首和 + 離散化 + 樹狀陣列)LeetCode陣列
- 二維字首和與差分、離散化技巧
- [演算法] 資料結構 splay(伸展樹)解析演算法資料結構
- 平衡二叉樹二叉樹
- 離散傅立葉變換
- 平衡二叉樹,B樹,B+樹二叉樹
- 【BZOJ3207】花神的嘲諷計劃Ⅰ hash+可持久化線段樹持久化
- 洛谷P3835 【模板】可持久化平衡樹持久化
- 【scikit-learn基礎】--『預處理』之 離散化
- 離散化的一道很經典的題
- 平衡二叉樹(AVL)二叉樹
- 平衡二叉樹AVL二叉樹
- 平衡樹學習筆記筆記
- 平衡樹 學習筆記筆記
- OpenCV 離散傅立葉變換OpenCV
- hdu5489 ||2015合肥網路賽1006 dp+離散化樹狀陣列優化陣列優化
- BZOJ 4195 程式自動分析【並查集+離散化】並查集