UOJ#349:【WC2018】即时战略 (LCT)

题目传送门:http://uoj.ac/problem/349


题目分析:WC评讲的时候就发现自己制杖,连LCT能动态链剖都忘了QAQ。

然后这个万年大坑今天终于被我填上了。

然后我在被UOJ过不了Extra test#3,被卡询问次数。改了很久都过不了,我索性弃疗了。(这绝对是场阴谋,逼我写替罪羊树维护动态点分树!)

LCT维护前驱后继,可以通过在Splay上记子树中最左最右实现。

扔个code上来就走。


CODE:

// RTS sample program

#include "rts.h"

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
#include<set>
using namespace std;

const int maxn=300100;

const long long M1=998244353;
const long long M2=1000000007;
const long long M3=1004535809;
typedef long long LL;
LL seed=0;

bool vis[maxn];
set <int> a,b;

struct Tnode
{
    int val,Left,Right,path_parent;
    bool flip;
    Tnode *son[2],*fa;

    int Get_d() { return (fa->son[1]==this); }
    void Connect(Tnode *P,int d) { (son[d]=P)->fa=this; }

    int Prev() { if (son[0]) return son[0]->Right; else return 0; }
    int Succ() { if (son[1]) return son[1]->Left; else return 0; }

    void Up()
    {
        Left=Right=val;
        if (son[0]) Left=son[0]->Left;
        if (son[1]) Right=son[1]->Right;
    }
    void Push_down()
    {
        if (flip)
        {
            swap(son[0],son[1]);
            if (son[0]) son[0]->flip^=1,swap(son[0]->Left,son[0]->Right);
            if (son[1]) son[1]->flip^=1,swap(son[1]->Left,son[1]->Right);
            flip=false;
        }
    }
} tree[maxn];
Tnode *Node[maxn];
int cur=-1;

int Rand()
{
    seed=(seed*M1+M2)%M3;
    return (int)seed;
}

int Get(int n)
{
    int x=Rand()%n+1;
    set <int> :: iterator p=a.lower_bound(x);
    if (p==a.end()) p--;
    return (*p);
}

void Solve1(int n)
{
    int c[2];
    c[0]=c[1]=1;
    while (!a.empty())
    {
        int i=Get(n);
        int x=Rand()&1,now=explore(c[x],i);
        if (vis[now]) x=(!x),now=explore(c[x],i);
        vis[now]=true;
        a.erase(now);
        while (now!=i) now=explore(now,i),vis[now]=true,a.erase(now);
        c[x]=i;
    }
}

Tnode *New_node(int v)
{
    cur++;
    tree[cur].val=tree[cur].Left=tree[cur].Right=v;
    tree[cur].path_parent=0;
    tree[cur].flip=false;
    tree[cur].fa=tree[cur].son[0]=tree[cur].son[1]=NULL;
    return tree+cur;
}

void Push(Tnode *P)
{
    if (!P) return;
    Push(P->fa);
    P->Push_down();
}

void Zig(Tnode *P)
{
    Tnode *F=P->fa;
    int d=P->Get_d();
    if (P->son[!d]) F->Connect(P->son[!d],d);
    else F->son[d]=NULL;
    if (F->fa) F->fa->Connect(P, F->Get_d() );
    else P->fa=NULL;
    P->Connect(F,!d);
    F->Up();
    P->path_parent=F->path_parent;
    F->path_parent=0;
}

void Splay(Tnode *P)
{
    Push(P);
    Tnode *F;
    while (P->fa)
    {
        F=P->fa;
        if (F->fa) ( P->Get_d()^F->Get_d() )? Zig(P):Zig(F);
        Zig(P);
    }
    P->Up();
}

/*int Get1(int n)
{
    int x=Rand()%n+1;
    set <int> :: iterator p=b.lower_bound(x);
    if (p==b.end()) p--;
    return (*p);
}*/

void Down(int x)
{
    Splay(Node[x]);
    Tnode *&tag=Node[x]->son[1];
    if (tag)
    {
        tag->fa=NULL;
        tag->path_parent=x;
        tag=NULL;
        Node[x]->Up();
    }
}

void Access(int x)
{
    Down(x);
    int y=Node[x]->path_parent;
    while (y)
    {
        Down(y);
        Node[y]->Connect(Node[x],1);
        Node[x]->path_parent=0;
        Node[y]->Up();
        x=y;
        y=Node[x]->path_parent;
    }
}

void Solve2(int n)
{
    //b.clear();
    //b.insert(1);
    for (int i=1; i<=n; i++) Node[i]=New_node(i);
    while (!a.empty())
    {
        int i=Get(n);
        int now=1,last=0;
        while (vis[now])
        {
            Splay(Node[now]);
            while (1)
            {
                Node[now]->Push_down();
                int Next=explore(now,i);
                if (Next==Node[now]->Prev()) now=Node[now]->son[0]->val;
                else
                    if (Next==Node[now]->Succ()) now=Node[now]->son[1]->val;
                    else
                    {
                        last=now;
                        now=Next;
                        break;
                    }
            }
        }

        while (now!=i)
        {
            Node[now]->path_parent=last;
            a.erase(now);
            //b.insert(now);
            vis[now]=true;
            last=now;
            now=explore(last,i);
        }
        Node[now]->path_parent=last;
        a.erase(now);
        //b.insert(now);
        vis[now]=true;
        Access(now);
    }
}

void play(int n, int T, int dataType) {
    a.clear();
    for (int i=2; i<=n; i++) a.insert(i);
    for (int i=1; i<=n; i++) vis[i]=false;
    vis[1]=true;

    if (dataType==3) Solve1(n);
    else Solve2(n);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值