2017东北地区赛D题 splay

题意:25W个序列 支持三个操作:

1 给你一个长度为偶数的区间 交换区间相邻的元素 区间里 第1个和第2个换 第3个和第4个换 第5个和第6个换

2 给你一个长度为奇数的区间 将区间翻转

3 求区间的和

题解:将区间元素按下标奇偶分成2个splay 对于第1个操作直接交换区间 第2个操作由于是奇数长度的区间 所以把范围两个splay内的区间直接翻转就好了

PS:场上没有想到按奇偶分组 然后一直在操作一讨论奇偶性,然后发现这似乎是个不可能的操作?GG 最后两个半小时几乎什么都没有干,就这样划水还拿了一等,如果是ICPC估计就真的GG了....... (我用自己的数据测的是对的,直到我发blog时网上还没有挂出比赛题)

#include <bits/stdc++.h>
using namespace std;
#define pf printf
#define ss system("pause");
#define ps puts("");
#define orz printf("orz\n");
#define maxn 550000
#define INF 0x3f3f3f3f
#define sint long long
int pfg;
inline int getint()
{
    int res=0,f=1;char c;
    while(c=getchar(),c<'0'||c>'9'){if(c=='-')f=-1;}
    res=c-'0';
    while(c=getchar(),c>='0'&&c<='9')res=res*10+c-'0';
    return res*f;
}
int tr[maxn][2],fa[maxn],root,n,m,rt0,rt1;
int v[maxn],val[maxn],a[maxn],siz[maxn],cnt;
sint sum[maxn];
bool rev[maxn];
void pushup(int rt)
{
    int l=tr[rt][0],r=tr[rt][1];
    siz[rt]=siz[l]+siz[r]+1;
    sum[rt]=sum[l]+sum[r]+val[rt];
}
void pushdown(int rt)
{
    if(rev[rt])
    {
        int l=tr[rt][0],r=tr[rt][1];
        rev[rt]^=1;rev[r]^=1;rev[l]^=1;
        swap(tr[l][0],tr[l][1]);swap(tr[r][0],tr[r][1]);
    }
}
void rotate(int x,int &rt)
{
    int l,r,z,y;
    y=fa[x];z=fa[y];
    if(x==tr[y][0]) l=0;
    else l=1;r=1^l;
    if(rt==y) rt=x;
    else
    {
        if(tr[z][0]==y) tr[z][0]=x;
        else tr[z][1]=x;
    }
    fa[x]=z;fa[y]=x;fa[tr[x][r]]=y;
    tr[y][l]=tr[x][r];tr[x][r]=y;
    pushup(y);pushup(x);
}
void splay(int x,int &rt)
{
    int y,z;
    while(x!=rt)
    {

        y=fa[x];z=fa[y];
        if(y!=rt)
        {
            if((tr[y][0]==x)^(tr[z][0]==y)) rotate(x,rt);
            else rotate(y,rt);
        }
        rotate(x,rt);
    }
}
int select(int now,int rk)
{
    if(rev[now]) pushdown(now);
    int l=tr[now][0],r=tr[now][1];
    int rak=siz[l]+1;
    if(rak==rk) return now;
    if(rak>rk) return select(l,rk);
    else return select(r,rk-rak);
}
void solve_rever(int x)
{
    rev[x]^=1;
    swap(tr[x][0],tr[x][1]);
}
void build(int l,int r,int f)
{
    if(l>r)return;
    int now=l,last=f;
    if(l==r)
    {
        sum[now]=val[now]=v[l]; fa[now]=last;siz[now]=1;
        if(l<f)tr[last][0]=now;
        else tr[last][1]=now;
        return;
    }
    int mid=(l+r)>>1;now=mid;
    build(l,mid-1,mid);
    build(mid+1,r,mid);
    val[now]=v[mid];fa[now]=last;
    pushup(now);
    if(mid<f)tr[last][0]=now;
    else tr[last][1]=now;
}
void get_trees()
{
    int l,r;
    cnt++;v[cnt]=0; l=cnt;
    for(int i=1;i<=n;i+=2)
    {
        cnt++;v[cnt]=a[i];
    }
    cnt++;v[cnt]=0; r=cnt;
    rt1=(l+r)>>1;
    build(l,r,0);

    cnt++;v[cnt]=0; l=cnt;
    for(int i=2;i<=n;i+=2)
    {
        cnt++;v[cnt]=a[i];
    }
    cnt++;v[cnt]=0; r=cnt;
    rt0=(l+r)>>1;
    build(l,r,0);

}
void solve_0(int l,int r)
{
    int odd_rt =l/2+1;
    int even_rt=(l-1)/2+1;
    int len =(r-l+1)/2;
    int x1,y1;
    x1=select(rt1,odd_rt);
    y1=select(rt1,odd_rt+len+1);

    splay(x1,rt1);
    splay(y1,tr[x1][1]);
    int x0,y0;
    x0=select(rt0,even_rt);
    y0=select(rt0,even_rt+len+1);
    splay(x0,rt0);
    splay(y0,tr[x0][1]);

    swap(fa[tr[y1][0]],fa[tr[y0][0]]);
    swap(tr[y1][0],tr[y0][0]);
    pushup(y1);pushup(x1);
    pushup(y0);pushup(x0);
}
void dfs(int rt)
{
    pushdown(rt);
    if(val[rt]) pf("%d %d %d\n",val[rt],sum[rt],fa[rt]);
    if(tr[rt][0]) dfs(tr[rt][0]);
    if(tr[rt][1]) dfs(tr[rt][1]);
}
void solve_1(int l, int r)
{
    int odd_rt   = l/2 + 1;
    int even_rt  =(l-1)/2 + 1;
    int odd_len  =(r-l)/2;
    int even_len = odd_len + 1;
    if (l&1) swap(odd_len,even_len);
    int x,y;

    x=select(rt1,odd_rt);
    y=select(rt1,odd_rt+odd_len+1);
    splay(x,rt1);
    splay(y,tr[x][1]);
    solve_rever(tr[y][0]);

    x=select(rt0,even_rt);
    y=select(rt0,even_rt+even_len+1);
    splay(x,rt0);
    splay(y,tr[x][1]);
    solve_rever(tr[y][0]);
}
sint qsum(int l, int r)
{
    int odd_rt=l/2 + 1;
    int even_rt=(l-1)/2 + 1;

    int odd_len=(r+1)/2-l/2;
    int even_len=r/2-(l-1)/2;
    sint ans=0;
    int x,y;

    x=select(rt1,odd_rt);
    y=select(rt1,odd_rt+odd_len+1);
    splay(x,rt1);
    splay(y,tr[x][1]);
    ans +=sum[tr[y][0]];

    x=select(rt0,even_rt);
    y=select(rt0,even_rt+even_len+1);
    splay(x,rt0);
    splay(y,tr[x][1]);
    ans +=sum[tr[y][0]];
    return ans;
}
int main()
{
    n=getint();
    for(int i=1;i<=n;i++) a[i]=getint();
    get_trees();
    int op,x,y,z;
    m=getint();
    for(int i=1;i<=m;i++)
    {
        op=getint();x=getint();y=getint();
        if(op==0) solve_0(x,y);
        if(op==1) solve_1(x,y);
        if(op==2) pf("%lld\n",qsum(x,y));
    }
    return 0;
}
/*
15
1 7 14 7 9 4 18 18 2 4 5 5 1 7 1
15
2 1 14
0 5 10
0 11 14
1 6 8
2 2 7
2 2 13
0 5 8
2 8 12
0 4 13
2 6 10
2 8 12
2 9 12
2 1 12
0 2 9
0 6 9
*/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值