bzoj2518: [Shoi2010]滚动的正四面体 线段树

写这个题的同学请提前做好心理准备。此题堪称史上最烦人的线段树了,和bzoj1018差不多。都是上海的线段树。尼玛为何都这么丧心病狂。。。结合14年的三叉神经树,上海的数据结构虽然都还停留在线段树阶段但代码量都是在250+,无力吐槽。

说说这个题怎么做吧。首先我们可以模拟出初始序列的样子。我大了一个表a[I][J][K]代表i为底面j为朝向我们的面向三个方向转后底面是哪个面。最好自己拿一个正四面体弄一下。

由于每个面都是正三角形所以向三个方向转不回有把倒三角一次转成正三角的情况。再加上我们记录了四面体的两个面我们就可以确定这个四面体了。

我对4个面的编号是这样的:以底面为新将四面体的其余三个面拆成一个倒三角。中间的面为1,起余的面从左上角开始顺时针增加编号。4号面就是那个面向我们的面。

然后问题就变成了维护区间的一个置换。例如换操作a,则要用第a个操作后原本的置换和改变后的置换组成一个新的置换。建议自己动手画一下。。。

然后区间除了维护置换以外还有一个置换后每个数所对应的元置换,元置换就是指向原来的置换所对应的数的一个置换。

估计已经把人绕晕了。。。。。。

粗略的来说就是某段区间的置换改变后,跟原来的置换有个关系,没有这个关系的话就无法统计置换后的各种颜色的情况。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define maxn 241000
int getint()
{
    char c;int res;
    while(c=getchar(),c<'0'||c>'9');
    res=c-'0';
    while(c=getchar(),c>='0'&&c<='9')
        res=res*10+c-'0';
    return res;
}
int n,m;
struct node
{
    int a[5];
}tr[maxn],ch[maxn],per[maxn],loop[5];
string led[5][5];
char st[61000];
int face[61000];
int a[10][10][10],flag[10][10];
int cal[maxn];
void clean(node &tmp)
{
    for(int i=1;i<=4;i++) tmp.a[i]=i;
}
void init()
{
    a[1][4][1]=2;a[1][4][2]=3;a[1][4][3]=4;
    a[1][2][1]=3;a[1][2][2]=4;a[1][2][3]=2;
    a[1][3][1]=4;a[1][3][2]=2;a[1][3][3]=3;
 
    a[2][1][1]=4;a[2][1][2]=3;a[2][1][3]=1;
    a[2][3][1]=1;a[2][3][2]=4;a[2][3][3]=3;
    a[2][4][1]=3;a[2][4][2]=1;a[2][4][3]=4;
 
    a[3][1][1]=2;a[3][1][2]=4;a[3][1][3]=1;
    a[3][2][1]=4;a[3][2][2]=1;a[3][2][3]=2;
    a[3][4][1]=1;a[3][4][2]=2;a[3][4][3]=4;
 
    a[4][1][1]=3;a[4][1][2]=2;a[4][1][3]=1;
    a[4][2][1]=1;a[4][2][2]=3;a[4][2][3]=2;
    a[4][3][1]=2;a[4][3][2]=1;a[4][3][3]=3;
 
    led[1][2]="01342";led[1][3]="01423";led[1][4]="01234";
    led[2][1]="02431";led[2][3]="02143";led[2][4]="02314";
    led[3][1]="03241";led[3][2]="03412";led[3][4]="03124";
    led[4][1]="04321";led[4][2]="04132";led[4][3]="04213";
}
void print(int rt)
{
    for(int i=1;i<=4;i++)
    {
        printf("%d ",ch[rt].a[i]);
    }
    for(int i=1;i<=4;i++)
    {
        printf("%d ",per[rt].a[i]);
    }
    for(int i=1;i<=4;i++)
    {
        printf("%d ",tr[rt].a[i]);
    }
    printf("\n");
    //system("pause");
}
void makeloop()
{
    for(int i=1;i<=4;i++)
    {
        loop[1].a[i]=led[2][1][i]-'0';
        loop[2].a[i]=led[3][1][i]-'0';
        loop[3].a[i]=led[4][1][i]-'0';
    }
}
node getback(node b,node a)
{
    node ans;
    for(int i=1;i<=4;i++)
    {
        ans.a[a.a[i]]=b.a[i];
    }
    return ans;
}
node change(node tmp,node res)
{
    node ans;
    for(int i=1;i<=4;i++)
    {
        ans.a[i]=res.a[tmp.a[i]];
    }
    return ans;
}
int save[61000];
void pushup(int rt)
{
    for(int i=1;i<=4;i++)
    {
        tr[rt].a[i]=tr[rt<<1].a[i]+tr[rt<<1|1].a[i];
    }
}
 
inline void doper(node &a,const node &perd)
{
    static int b[5];
    int i;
    for(i=1;i<=4;i++){
        b[i]=a.a[i];
    }
    for(i=1;i<=4;i++){
        a.a[i]=perd.a[b[i]];
    }
}
inline void doper(int *a,const node &perd)
{
    static int b[5];
    int i;
    for(i=1;i<=4;i++){
        b[i]=a[i];
    }
    for(i=1;i<=4;i++){
        a[perd.a[i]]=b[i];
    }
}
 
void update(int l,int r,int rt)
{
    if(l==r)
    {
        doper(ch[rt],per[rt]);
        for(int i=1;i<=4;i++) tr[rt].a[i]=0;
        tr[rt].a[ch[rt].a[1]]++;
        clean(per[rt]);
    }
    else
    {
        pushup(rt);
        doper(tr[rt].a,per[rt]);
        doper(ch[rt],per[rt]);
    }
}
void pushdown(int l,int r,int rt)
{
    if(l==r) return;
    int mid=(l+r)>>1;
    per[rt<<1]=change(per[rt<<1],per[rt]);
    per[rt<<1|1]=change(per[rt<<1|1],per[rt]);
    update(lson);
    update(rson);
    clean(per[rt]);
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        int now=save[l],tous=face[l];
        for(int i=1;i<=4;i++) ch[rt].a[i]=led[now][tous][i]-'0';
        clean(per[rt]);
        tr[rt].a[save[l]]=1;
        return;
    }
    clean(ch[rt]);clean(per[rt]);
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    update(l,r,rt);
}
int query(int l,int r,int rt,int x,int y)
{
    //printf("%d %d %d %d %d\n",l,r,rt,x,y);
 
    if(x<=l&&r<=y)
    {
        return tr[rt].a[1];
    }
    int mid=(l+r)>>1;
    pushdown(l,r,rt);
    //print(rt);
    int tmp=0;
    if(x<=mid) tmp+=query(lson,x,y);
    if(y>mid) tmp+=query(rson,x,y);
    return tmp;
}
node query2(int l,int r,int rt,int x)
{
    if(l==r)
    {
        return ch[rt];
    }
    int mid=(l+r)>>1;
    pushdown(l,r,rt);
    //printf("%d %d %d\n",l,r,rt);
    //print(rt);
    if(x<=mid) return query2(lson,x);
    return query2(rson,x);
}
void add(int l,int r,int rt,int x,int y,node v)
{
    if(x<=l&&r<=y)
    {
        per[rt]=change(per[rt],v);
        update(l,r,rt);
        return;
    }
    int mid=(l+r)>>1;
    pushdown(l,r,rt);
    if(x<=mid) add(lson,x,y,v);
    if(y>mid) add(rson,x,y,v);
    update(l,r,rt);
}
node makenew(node kk,int v)
{
    int now=kk.a[1],fac=kk.a[4],tmp;
    tmp=now;
    now=a[now][fac][v];
    fac=tmp;
    node ans;
    for(int i=1;i<=4;i++) ans.a[i]=led[now][fac][i]-'0';
    return ans;
}
node gettnow(node aa,node bb)
{
    node ans;
    for(int i=1;i<=4;i++)ans.a[aa.a[i]]=bb.a[i];
    return ans;
}
int main()
{
    //freopen("tetrahedron1.in","r",stdin);
    init();
    scanf("%d",&n);
    scanf("%s",st+1);
    save[1]=1;face[1]=4;
    int now=1,fac=4,tmp;
    for(int i=1;i<=n;i++)
    {
        if(st[i]=='L') tmp=1;
        if(st[i]=='R') tmp=2;
        if(st[i]=='B') tmp=3;
        save[i+1]=a[now][fac][tmp];
        face[i+1]=now;
        fac=now;now=save[i+1];
    }
    makeloop();
    n++;
    build(1,n,1);
    scanf("%d",&m);
    int op,a,b;
    char str[10];
    for(int i=1;i<=m;i++)
    {
        op=getint();
        if(op==1)
        {
            a=getint();b=getint();
            printf("%d\n",query(1,n,1,a,b));
        }
        else
        {
            //printf("orz\n");
            a=getint();b=n;
 
            scanf("%s",str);
            if(str[0]=='L') tmp=1;
            if(str[0]=='R') tmp=2;
            if(str[0]=='B') tmp=3;
 
            node kk=query2(1,n,1,a),now1,now2,tnow;
            //for(int i=1;i<=4;i++)printf("%d ",kk.a[i]);puts("");
            now1=makenew(kk,tmp);
           // for(int i=1;i<=4;i++)printf("%d ",now1.a[i]);puts("");
            if(st[a]=='L') tmp=1;
            if(st[a]=='R') tmp=2;
            if(st[a]=='B') tmp=3;
            now2=makenew(kk,tmp);
            //for(int i=1;i<=4;i++)printf("%d ",now2.a[i]);puts("");
            tnow=gettnow(now2,now1);
            //for(int i=1;i<=4;i++)printf("%d ",tnow.a[i]);puts("");
            add(1,n,1,a+1,b,tnow);
            st[a]=str[0];
        }
    }
    return 0;
}
/*
5
LLLLB
3
1 3 6
0 3 R
1 3 6
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值