BZOJ 2002 弹飞绵羊
某天全是数据结构的考试题T3
在我学LCT之前就在轩神的博客中看到过这个归类在LCT里,所以事先知道了算法,不过这个貌似也挺明显的。(虽然分块更好写)
考场上为了证明哇我会写LCT诶就强行打了只打过一遍的LCT,然后Debug两个小时。。。最后还一不小心交了一个没debug的版本。。
//Twenty debug两个小时
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#define lc ch[x][0]
#define rc ch[x][1]
using namespace std;
const int maxn=2e5+299;
int opt,xx,yy,zz,k[maxn],sz[maxn],p[maxn],ch[maxn][2],flip[maxn],n,m;
inline int read(){
int ret=0,f=1; char ch=getchar();
while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
return ret*f;
}
void update(int x) {sz[x]=sz[lc]+sz[rc]+1;}
bool isroot(int x) {return (ch[p[x]][1]!=x&&ch[p[x]][0]!=x);}
void build(int i,int x){
k[i]=x;
sz[i]=1;
if(i+k[i]<=n) p[i]=i+k[i];
else p[i]=n+1;
}
void rotate(int x){
int y=p[x],z=p[y],l=(x==ch[y][1]),r=l^1;
if(!isroot(y)) ch[z][y==ch[z][1]]=x; p[x]=z;
ch[y][l]=ch[x][r]; p[ch[y][l]]=y;
ch[x][r]=y; p[y]=x;
update(y); update(x);
}
void splay(int x){
for(;!isroot(x);rotate(x)){
int y=p[x],z=p[y];
if(!isroot(y)) ((x==ch[y][1])^(y==ch[z][1]))?rotate(x):rotate(y);
}
}
void access(int x){
for(int t=0;x;x=p[t=x]){
splay(x);
rc=t;
update(x);
}
}
void cut(int a,int b){
access(b);
splay(b);
p[ch[b][0]]=0;ch[b][0]=0;//p[a]=0; 多了假根 a不一定是左儿子
update(b);
}
int main()
{
freopen("bounce.in","r",stdin);
freopen("bounce.out","w",stdout);
n=read();
for(int i=1;i<=n;i++) build(i,read());
m=read(); sz[n+1]=1;//若将根点sz设为0 update时会出错 ,若不设根点翻转时似乎会出一些不可言喻的错
while(m--){
opt=read(); xx=read();xx++;
if(opt==1){
access(xx);
splay(xx);
printf("%d\n",sz[xx]-1);
}
else{
yy=read();
/*if(xx+k[xx]<=n&&xx+yy<=n) cut(xx+k[xx],xx);
//else cut(n+1,xx); //若将根Cut会出现不可言喻的错误
if(xx+yy<=n) p[xx]=xx+yy;
//else p[xx]=n+1;
else if(xx+k[xx]<=n) p[xx]=n+1;
k[xx]=yy; */ //这个把不是假根改成是假根就错了。。。。
int now=min(n+1,yy+xx),last=min(k[xx]+xx,n+1);
if(now!=last){
cut(last,xx);
p[xx]=now;
k[xx]=yy;
}
}
}
return 0;
}
另两种写法以后什么时候再来填坑把。
-------------------------------------------------更新---------------------------------------------------
2.分块
第一次写这样的分块吧,之前打的分块都是乱搞一些线段树的题基本。每个点维护跳出块需要多少步和跳到的点。每次修改就暴力修改一个块内的该点前面的部分。
//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int maxn=200000+299;
int n,m,fa[maxn],belong[maxn],nxt[maxn],step[maxn],gs,o,x,y;
void modify(int x,int y) {
if(belong[x]!=belong[y]) {
nxt[x]=y;
step[x]=1;
}
else {
step[x]=step[y]+1;
nxt[x]=nxt[y];
}
}
int main() {
scanf("%d",&n);
for(int i=0;i<n;i++) {
scanf("%d",&fa[i]);
fa[i]=min(i+fa[i],n);
}
gs=sqrt(2*n)+1;
for(int i=0;i<n;i++)
belong[i]=i/gs;
belong[n]=-1;
for(int i=n-1;i>=0;i--) modify(i,fa[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++) {
scanf("%d%d",&o,&x);
if(o==1) {
int tp=x,ans=0;
while(tp!=n) {
ans+=step[tp];
tp=nxt[tp];
}
printf("%d\n",ans);
}
else {
scanf("%d",&fa[x]);
fa[x]=min(fa[x]+x,n);
for(int i=x;i>=0&&belong[i]==belong[x];i--)
modify(i,fa[i]);
}
}
return 0;
}
---------------------------------------------2018-3-7更新---------------------------------------
现在看以前的博客觉得自己真的好蠢啊。。
时隔多年来补splay维护括号序列的写法。
看代码就能理解,没什么好说的。自底向上的splay真是奥妙重重。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
const int N=400007;
typedef long long LL;
using namespace std;
int n,m;
template<typename T>void read(T &x) {
char ch=getchar(); x=0; T f=1;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
int ecnt,fir[N],nx[N],to[N];
void add(int u,int v) {
nx[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
}
int dfs_clock,dfn[2][N],v[N];
void dfs(int x) {
v[dfn[0][x]=++dfs_clock]=1;
for(int i=fir[x];i;i=nx[i])
dfs(to[i]);
v[dfn[1][x]=++dfs_clock]=-1;
}
int tot,p[N],sum[N],ch[N][2];
#define lc ch[x][0]
#define rc ch[x][1]
void update(int x) { sum[x]=v[x]; if(lc) sum[x]+=sum[lc]; if(rc) sum[x]+=sum[rc]; }
int build(int sz) {
if(sz<=0) return 0;
int ls=build(sz>>1);
int x=++tot;
int rs=build(sz-(sz>>1)-1);
lc=ls; rc=rs;
if(lc) p[lc]=x;
if(rc) p[rc]=x;
update(x);
return x;
}
void rotate(int x) {
int y=p[x],z=p[y],l=(x==ch[y][1]),r=l^1;
if(z) ch[z][y==ch[z][1]]=x; p[x]=z;
ch[y][l]=ch[x][r]; p[ch[x][r]]=y;
ch[x][r]=y; p[y]=x;
update(y); update(x);
}
void splay(int x) {
for(;p[x];rotate(x)) {
int y=p[x],z=p[y];
if(z) ((x==ch[y][1])^(y==ch[z][1]))?rotate(x):rotate(y);
}
}
int nxt(int x) {
splay(x); x=rc;
while(lc) x=lc;
splay(x); return x;
}
int pre(int x) {
splay(x); x=lc;
while(rc) x=rc;
splay(x); return x;
}
int split(int x) { //x作为左边最后一个
splay(x); int y=rc;
p[y]=rc=0;
update(x); return y;
}
void merge(int x,int y) {
splay(x); splay(y);
while(rc) x=rc; splay(x);
rc=y; p[y]=x; update(x);
}
int main() {
read(n);
for(int i=1;i<=n;i++) {
int fa; read(fa);
fa=min(fa+i,n+1);
add(fa,i);
}
dfs(n+1);
int x=2*(n+1)+1,y=x+1;
ch[x][1]=y; p[y]=x;
ch[y][0]=build(2*(n+1));
p[ch[y][0]]=y; tot=y;
update(y); update(x);
read(m);
while(m--) {
int o,u,fa;
read(o); read(u); u++;
if(o==1) {
int x=nxt(dfn[0][u]);
printf("%d\n",sum[lc]-1);
}
else {
read(fa); fa=min(fa+u,n+1);
int l=pre(dfn[0][u]);
split(l);
int r=split(dfn[1][u]);
merge(l,r);
split(dfn[0][fa]);
merge(dfn[0][fa],dfn[1][u]);
merge(dfn[1][u],dfn[1][fa]);
}
}
return 0;
}
/*
4
1 2 1 1
3
1 1
2 1 1
1 1
*/