一次没有苟住的模拟赛

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hwzzyr/article/details/81944661

GG!!!


今天的这一套题本来以为有380(四道题来着),但是后面两道题GG了。
前两题暂且不谈。
我们来看看第三题

【BZOJ2438】杀人游戏
Description
一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 N 个人里面,查出谁是杀手。
警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民。 假如查证的对象是杀手, 杀手将会把警察干掉。
现在警察掌握了每一个人认识谁。
每一个人都有可能是杀手,可看作他们是杀手的概率是相同的。
问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多少?
Input
第一行有两个整数 N,M。
接下来有 M 行,每行两个整数 x,y,表示 x 认识 y(y 不一定认识 x) 。
Output
仅包含一行一个实数,保留小数点后面 6 位,表示最大概率。
Sample Input
5 4
1 2
1 3
1 4
1 5
Sample Output
0.800000

说明:警察只需要查证 1。假如1是杀手,警察就会被杀。假如 1不是杀手,他会告诉警察 2,3,4,5 谁是杀手。而 1 是杀手的概率是 0.2,所以能知道谁是杀手但没被杀的概率是0.8。
Hint
【数据规模与约定】
对于 100%的数据有 1 N 10 0000,0&≤M≤&300000

显然,访问一个平民之后,他能够认识的人都可以访问而不会导致警察被杀。
所以,将原有关系图缩点之后,我们把所有入度为0的联通块询问一次就好了。
注意:我们还有一个需要特判的地方:
对于孤立的联通块,如果它不会影响接下来联通块的度数(减去之后入度不为0),那么就可以不算,而且多个独立联通块也只能不算一个
唉。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
const int Maxn=100005,Maxm=300005;
inline int read() {
    char c; int rec=0;
    while((c=getchar())<'0'||c>'9');
    while(c>='0'&&c<='9') rec=rec*10+c-'0',c=getchar();
    return rec;
}
int n,m;
struct Branch {int next,to;} branch[Maxm];
int h[Maxn],cnt=0;
inline void add(int x,int y) {
    branch[++cnt].to=y; branch[cnt].next=h[x]; h[x]=cnt; return ;
}
int Scc=0,bl[Maxn],d[Maxn],size[Maxn];
int dfn[Maxn],low[Maxn],ind=0;
int S[Maxn],vis[Maxn],top=0;
void Tarjan(int v) {
    dfn[v]=low[v]=++ind;
    S[++top]=v; vis[v]=1;
    for(int i=h[v];i;i=branch[i].next) {
        int j=branch[i].to;
        if(!dfn[j]) Tarjan(j),low[v]=min(low[v],low[j]);
        else if(vis[j]) low[v]=min(low[v],dfn[j]);
    }
    if(dfn[v]==low[v]) {
        int p=0; ++Scc;
        while(p!=v) {
            p=S[top--]; vis[p]=0; bl[p]=Scc; ++size[Scc];
        }
    } return ;
}
vector<int> into[Maxn];
int main() {
    n=read(); m=read();
    for(int i=1,x,y;i<=m;++i)
        x=read(),y=read(),add(x,y);
    for(int i=1;i<=n;++i) if(!dfn[i]) Tarjan(i);
    for(int v=1;v<=n;++v) {
        for(int i=h[v];i;i=branch[i].next) {
            int j=branch[i].to;
            if(bl[j]!=bl[v]) {
                into[bl[v]].push_back(bl[j]);
                ++d[bl[j]];
            }
        }
    }
    int tot=0;
    for(int i=1;i<=Scc;++i)
        if(d[i]==0) ++tot;
    for(int i=1;i<=Scc;++i)
        if(d[i]==0&&size[i]==1) {
            int flag=1;
            for(int j=0;j<into[i].size();++j)
                if(d[into[i][j]]==1) {
                    flag=0; break;
                }
            if(flag) {
                --tot; break;
            }
        }
    double ans=(double)(n-tot)/n;
    printf("%.6lf",ans);
    return 0;
}

接下来是第四题

【BZOJ3133】装球机器
Description
有一个装球机器,构造可以看作是一棵树。有下面两种操作:
从根放入一个球,只要下方有空位,球会沿着树滚下。如果同时有多个点可以走,那么会选择编号最小的节点所在路径的方向。比如依次在树根4放2个球,第一个球会落到1,第二个会落到3:

从某个位置拿走一个球,那么它上方的球会落下来。比如依次拿走5, 7, 8三个球:

Input
第一行:球的个数N,操作个数Q (N, Q <= 100 000)下面N行:第i个节点的父亲。如果是根,则为0 接下来Q行:op num
op == 1:在根放入num个球
op == 2:拿走在位置num的球
Output
保证输入合法
op == 1:输出最后一个球落到了哪里
op == 2:输出拿走那个球后有多少个球会掉下来
Sample Input
8 4
0
1
2
2
3
3
4
6
1 8
2 5
2 7
2 8
Sample Output
1
3
2
2

这道题很显然啊,球从根节点掉下来一定是一个规定的数列。
用线段树维护这个数列,然后再维护一个原树上的倍增数组,每次查找最高的有球的节点。
但是啊。。。我 T M 居然没有在线段树的时候开Maxn*4
Re成30分。。。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
const int Maxn=100005;
inline int read() {
    char c; int rec=0;
    while((c=getchar())<'0'||c>'9');
    while(c>='0'&&c<='9') rec=rec*10+c-'0',c=getchar();
    return rec;
}
int n,m,root;
struct Branch {int next,to;} branch[Maxn];
int h[Maxn],cnt=0;
inline void add(int x,int y) {
    branch[++cnt].to=y; branch[cnt].next=h[x]; h[x]=cnt; return ;
}
int deep[Maxn],fa[Maxn][18];
int minn[Maxn],id[Maxn],pos[Maxn],ind=0;
void Get_minn(int v) {
    minn[v]=v; deep[v]=deep[fa[v][0]]+1;
    for(int i=1;i<18;++i)
        fa[v][i]=fa[fa[v][i-1]][i-1];
    for(int i=h[v];i;i=branch[i].next){
        int j=branch[i].to; fa[j][0]=v;
        Get_minn(j); minn[v]=min(minn[v],minn[j]);
    } return ;
}
vector < pair<int,int> > temp[Maxn];
void Get_order(int v) {
    for(int i=h[v];i;i=branch[i].next) {
        int j=branch[i].to;
        temp[v].push_back(make_pair(minn[j],j));
    }
    sort(temp[v].begin(),temp[v].end());
    for(int i=0;i<temp[v].size();++i)
        Get_order(temp[v][i].second);
    id[v]=++ind; pos[ind]=v;
    return ;
}
int last;
struct Segment_Tree {
    int L,R,size,C;
} tree[Maxn<<2];
inline void Pushup(int v) {tree[v].size=tree[v<<1].size+tree[v<<1|1].size; return ;}
inline void Build(int v,int L,int R) {
    tree[v].L=L; tree[v].R=R; tree[v].size=tree[v].C=0;
    if(L==R) return ; int mid=(L+R)>>1;
    Build(v<<1,L,mid); Build(v<<1|1,mid+1,R);
    return ;
}
inline void Same(int v) {
    tree[v].size=tree[v].R-tree[v].L+1; tree[v].C=1; return ;
}
inline void Pushdown(int v) {
    if(tree[v].C) {Same(v<<1); Same(v<<1|1); tree[v].C=0;} return ;
}
inline void Cover(int v,int x) {
    if(tree[v].L==tree[v].R) {tree[v].size=1; last=tree[v].L; return ;}
    Pushdown(v);
    int lrest=tree[v<<1].R-tree[v<<1].L+1-tree[v<<1].size;
    if(lrest>=x) Cover(v<<1,x);
    else Same(v<<1),Cover(v<<1|1,x-lrest);
    Pushup(v); return ;
}
inline void Clear(int v,int p) {
    if(tree[v].L>p||tree[v].R<p) return ;
    if(tree[v].L==tree[v].R) {tree[v].size=0; tree[v].C=0; return ;}
    Pushdown(v);
    Clear(v<<1,p); Clear(v<<1|1,p);
    Pushup(v); return ;
}
inline int Ask(int v,int p) {
    if(tree[v].L>p||tree[v].R<p) return 0;
    if(tree[v].L==tree[v].R) return tree[v].size;
    Pushdown(v);
    return Ask(v<<1,p)+Ask(v<<1|1,p);
}
int main() {
    n=read(); m=read();
    for(int i=1;i<=n;++i) {
        int x=read();
        if(x) add(x,i);
        else root=i;
    }
    Get_minn(root); Get_order(root); Build(1,1,n);
    for(int i=1;i<=m;++i) {
        int opt=read(),x=read();
        if(opt==1) {
            Cover(1,x); 
            cout<<pos[last]<<'\n';
        }
        else {
            int temp=deep[x];
            for(int i=17;~i;--i)
                if(Ask(1,id[fa[x][i]])) x=fa[x][i];
            Clear(1,id[x]);
            cout<<temp-deep[x]<<'\n';
        }
    }
}

就是这样吧。。。

猜你喜欢

转载自blog.csdn.net/hwzzyr/article/details/81944661
今日推荐