【原创题】英勇赛尔,智慧童年!

第一道原创题,,然后第一题就标程出锅了,验题也没验出来orz,太可怕了。 如有重题,纯属巧合。 luogu提交处(最后20%分没有上传)

英勇赛尔,智慧童年!

出题人:newuser 验题人:phoenix (saier.cpp/in/out) 空间128M 时间1500ms

题目背景

作为一道优秀的NK互测题,我们需要一道精灵之间打架的差分约束题。 点亮生命的火种 穿梭在浩瀚的太空 追逐那神秘的力量 飒爽英姿蓝色旋风 英勇无畏的赛尔 智慧让我无可阻挡 精灵赐予我力量 心灵就是那战场 起飞吧 英勇智慧的赛尔号

问题描述

以上背景与题目关系很大。我们假设我们的主角赛小息来到了一个叫做NK星的地方,这里的精灵有五种属性,分别是火土水风雷。他们的关系已如下。白色的箭头指克,黑色的箭头指生。(例如水克火,土克雷以及风生雷,水生风) 在这个星球上,迷糊的赛小息将他的n个精灵的属性搞混了。卡璐璐和阿铁打决定帮助赛小息回忆一些信息。卡璐璐可以帮助回忆克制信息,阿铁打可以帮助回忆相生信息,赛小息在感觉信息不对劲的时候会遗忘(撤销)末尾一些信息(可以撤回掉之前的撤回)。 给定T个时刻,每个时刻给出opt,opt为1,卡璐璐给出”克”信息,为2,阿铁打给出”生”信息,为3,赛小息撤回一些信息。他们需要机智的你给出这些精灵的一种方案。为了出题人方便不写SPJ,你只需要每个时刻的最后判断是否合法就可以了。

输入格式:

第1行 一个整数n和一个整数T。 第2行至1+T行,每行一个整数opt. Opt==1输入两个整数x和 y 变换之后 表示x克y Opt==2输入两个整数x和 y 变换之后 表示x生y Opt==3输入一个整数x,变换之后 表示遗忘末尾的x次操作信息,(可能会遗忘之前的遗忘(你可以将遗忘也看做一次信息,因此也可以遗忘掉之前的遗忘) ,保证不会非法)

输出格式

T行 每行一个字符串,”true”表示合法,”false”表示非法(没有引号!)

样例输入1:

5 5
1 3 4
2 4 2
2 2 3
3 1
2 3 2

样例输出1:

true
true
true
true
false

样例输入2:

20 20
1 1 2
1 2 3
1 3 4
1 4 5
1 5 6
1 6 7
1 7 8
1 8 9
1 9 10
1 10 11
1 11 12
1 12 13
1 13 14
1 14 15
1 15 16
1 16 17
1 17 18
1 18 19
1 19 20
1 20 1
​
 

样例输出2:

true
true
true
true
true
true
true
true
true
true
true
true
true
true
true
true
true
true
true
true
  ​

数据范围

对于其中10%数据有 T<=8,n<=8 对于其中20%数据有T<=50,n<=30(其中5%数据无3操作) 对于其中20%数据有T<=5000,n<=3000 对于其中30%数据有T<=200000,n<=100000 (其中10%数据无3操作) 对于其中20%数据有T<=2000000,n<=1000000(其中5%数据无3操作) 对于100%的数据T<=1000000,n<=800000,保证数据完全随机由于出题人出不来非随机数据

特殊说明:

由于本题读入数据量很大,为保证控制读入效率,这里提供一段读入的代码(本代码会增加程序消耗内存请自行控制内存使用) 你只要把下面的代码贴到你的代码中,然后使用read(x)读入一个整数。 注意它使用了fread,请不要与scanf和cin混用,本地测试的时候读入要使用文件。 本题不强制使用读入优化的代码,你可以自由选择用什么方式读入。无论用什么代码,请都自行测试,并且自己承担相应的风险。需要#include<ctype.h> < pre class="lang:default decode:true">namespace handsome { ​ char buf[1<<20],p1,p2; ​ #define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:p1++) inline int R() { char t=GC; int x=0; while(!isdigit(t)) t=GC; while(isdigit(t)) x=x10+t-48,t=GC; return x; } } using namespace handsome; 比如下面是一个A+B的代码的例子:
#include
using namespace std;
namespace handsome{
// ....
};
​
using namespace handsome;
int a,b;
​
int main() {
a=R();
b=R();
printf("%d\n",a+b);
}

题解:

本题有一个很sao的撤回操作,对于这些操作,其实我们可以这样来看-->在没有撤回操作来看,其实就是从0->1->2->3->.....->m,将每个操作看作一个节点,那么就是一条链的遍历。那么对于i号操作是撤回操作,并撤回x条消息,我们就可以看作是他将连在了i-x-1下,以i-x-1为父亲地继续向下进行遍历。 那么在离线的情况下,我们这样构出了一颗dfs树,这样就可以忽视掉撤回的影响了,只是这样我们维护答案的时候必须需要一种可持久化(或者可撤回的)数据结构来维护,使得我们可以在dfs回溯的时候去除这一次操作的影响。 考虑完撤回的影响之后,我们再回头看本题。本题维护如图所示的一个精灵之间的生克关系。基本上就是一眼的带权并查集,只是在路径压缩之后的 并查集并不是如我们之前所想的那样是一个可持久化的数据结构,如果不加任何优化,时间复杂度又肯定错的。那么我们其实只需要在并查集合并的时候,按秩合并一下就可以了。判断一下两个并查集哪个的size更大,将size小的那个并查集插到size大的那个 并查集下面就可以了。 同时,我们将每次并查集添加进去的时候,将在下面的那个添加到另一个栈里面,这样我们在dfs回溯的时候,就可以取出栈中的元素,然后撤销掉并查集的操作就可以了。这样我们就完成了并查集的可持久化。 并查集由于是按秩合并了,没有路径压缩,每次的期望树高是O(log2(n)),每次并查集操作的时间复杂度就变成了O(log2(n))。最终时间复杂度(nlog2(n))(n与T同阶,忽略字母). Newuser's LJ code:
/*A KE B val[a]-val[b]=2
A sheng B val[b]-bal[a]=1
*/
#include
#include
#include
#include
#define mp make_pair
using namespace std;
const int maxn = 1000005;
int n,T,fa[maxn],siz[maxn];
struct node {
    int opt,x,y;
}z[maxn];
int en[maxn],nt[maxn],la[maxn],owo;
void addedge(int x,int y) {
    en[++owo]=y; nt[owo]=la[x]; la[x]=owo;
}
int val[maxn],bcj[maxn];

namespace handsome {

char buf[1<<20],*p1,*p2;
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)
inline int R()
{
    char t=GC;
    int x=0;
    while(!isdigit(t)) t=GC;
    while(isdigit(t)) x=x*10+t-48,t=GC;
    return x;
}

};
using namespace handsome;

bool ANS[maxn];
int now = 0;
int sta[maxn],top;
pairgf(int x) {
    int sum = 0;
    while(bcj[x]!=x) {
        sum=sum+val[x]; x=bcj[x];
    }
    return mp(x,sum);
}

inline int mo(int x) {
    x%=5; if(x<0) x+=5; return x; 
}
void chexiao() {
    int x = sta[top--];
    if(x==-1) return;
    siz[bcj[x]] -= siz[x];
    val[x] = 0; bcj[x] = x;
}
int aha(int x,int y,int cj) {
    pairtmpx = gf(x); pairtmpy = gf(y);
    int fx = tmpx.first; int fy = tmpy.first;
    if(tmpx.first==tmpy.first) {
        if(mo(mo(tmpx.second)-mo(tmpy.second))!=cj) 
        return 0;
        else sta[++top]=-1;
    } else {
        if(siz[fx]>siz[fy]) {
            bcj[fy] = fx;
            val[fy] = -tmpy.second + tmpx.second - cj;
            siz[fx] += siz[fy];
            sta[++top] = fy;
        } else {
            bcj[fx] = fy; 
            val[fx] = tmpy.second - tmpx.second + cj;
            siz[fy] += siz[fx];
            sta[++top] = fx;
        }
    }
    return 1;
}
void dfs(int x,int ba) {
    if(x==0) {
        for(int it=la[x];it;it=nt[it]) dfs(en[it],x);
        return;
    }
    fa[x] = ba; 
    if(!ANS[ba]) 
        ANS[x] = 0;
    else {
        if(z[x].opt==3)
        {
          ANS[x] = ANS[fa[x]];
          if(ANS[x]==1) sta[++top]=-1;
        }
        else if(z[x].opt==2) {
            if(aha(z[x].x,z[x].y,4)) ANS[x] = 1; 
            else ANS[x] = 0;
        } else {
            if(aha(z[x].x,z[x].y,2)) ANS[x] = 1; 
            else ANS[x] = 0;
        }
    }
    for(int it=la[x];it;it=nt[it]) dfs(en[it],x);
    if(ANS[ba]&&ANS[x]) { chexiao(); }
}
int main() {
//  freopen("saier.in","r",stdin);
//  freopen("saier.out","w",stdout);
    n=R(); T=R();
    for(int i=1;i<=n;i++) bcj[i]=i,siz[i]=1;
    for(int i=1;i<=T;i++) {
        z[i].opt = R(); z[i].x = R();
        if(z[i].opt==3) {
            now-=z[i].x; 
        }
        else  z[i].y = R();
        addedge(now,i); now = i;
    }   
    ANS[0] = 1;
    dfs(0,0);
    for(int i=1;i<=T;i++)  {
        if(ANS[i]) printf("true\n");
        else printf("false\n");
    }
}
Skywalker's excellent code:
#include
#include
#include
using namespace std;
const int N = 1000005;
char buf[1<<20],*p1,*p2;
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)
inline void R(int &x)
{
    char t=GC;
    x=0;
    while(!isdigit(t)) t=GC;
    while(isdigit(t)) x=x*10+t-48,t=GC;
}

int n,m;
struct node
{
    int op,x,y;
}ask[N];
int Last[N],Next[N],End[N],cnt;
bool ans[N];
int fa[N],dis[N],dep[N];

void Add(int x,int y)
{
    cnt++;
    End[cnt]=y;
    Next[cnt]=Last[x];
    Last[x]=cnt;
}

int GetFa(int x,int &d)
{
    if(fa[x]==x){d=0; return x;}
    int fx=GetFa(fa[x],d);
    d+=dis[x];
    return fx;
}

void DFS(int u,bool flag)
{
    if(flag)
    {
        ans[u]=1;
        for(int i=Last[u];i;i=Next[i])
        {
            int v=End[i];
            DFS(v,flag);
        }
        return ;
    }
    int op=ask[u].op,x=ask[u].x,y=ask[u].y;
    if(op==1){
        int fx,fy,d1,d2,d,add=0;
        fx=GetFa(x,d1);
        fy=GetFa(y,d2);
        int tmp=(d1+(5-d2%5))%5;
        if(fx==fy) tmp==3?flag=0:flag=1;
        else
        {
            if(dep[fx]>dep[fy]) swap(fx,fy),d=d1-d2+2;
            else d=d2-d1+3;
            d=(d%5+5)%5;
            fa[fx]=fy,dis[fx]=d;
            if(dep[fx]==dep[fy]) dep[fy]++,add=1;
        }
        if(flag) ans[u]=1;
        for(int i=Last[u];i;i=Next[i])
        {
            int v=End[i];
            DFS(v,flag);
        }
        if(fx!=fy) fa[fx]=fx;dis[fx]=0,dep[fy]-add;
    }
    else if(op==2){
        int fx,fy,d1,d2,d,add=0;
        fx=GetFa(x,d1);
        fy=GetFa(y,d2);
        int tmp=(d1+(5-d2%5))%5;
        if(fx==fy) tmp==1?flag=0:flag=1;
        else
        {
            if(dep[fx]>dep[fy]) swap(fx,fy),d=d1-d2+4;
            else d=d2-d1+1;
            d=(d%5+5)%5;
            fa[fx]=fy,dis[fx]=d;
            if(dep[fx]==dep[fy]) dep[fy]++,add=1;
        }
        if(flag) ans[u]=1;
        for(int i=Last[u];i;i=Next[i])
        {
            int v=End[i];
            DFS(v,flag);
        }
        if(fx!=fy) fa[fx]=fx,dis[fx]=0,dep[fy]-=add;
    }
    else{
        for(int i=Last[u];i;i=Next[i])
        {
            int v=End[i];
            DFS(v,flag);
        }
    }
}

int main()
{
//  freopen("saier.in","r",stdin);
//  freopen("saier.out","w",stdout);
    int i;
    R(n),R(m);
    for(i=1;i<=n;i++) fa[i]=i,dep[i]=1,dis[i]=0;
    for(i=1;i<=m;i++)
    {
        R(ask[i].op),R(ask[i].x);
        if(ask[i].op!=3)
        {
            R(ask[i].y);
            Add(i-1,i);
        }
        else Add(i-ask[i].x-1,i);
    }
    DFS(0,0);
    for(i=1;i<=m;i++) 
        ans[i]?puts("false"):puts("true");
    return 0;
}
最后:作为Skyfuker的小迷弟Newesur :%%%sto sto sto !Skywalker! orz orz orz%%%
posted @ 2018-10-07 14:16  Newuser233  阅读(12)  评论(0)    收藏  举报