bzoj5003: 与链 5004: 开锁魔法II 5005:乒乓游戏

www.lydsy.com/JudgeOnline/upload/task.pdf

第一题题意可以转为选一个长度k的序列,每一项二进制的1的位置被下一项包含,且总和为1,考虑每个二进制位的出现位置,可以转化为一个多重背包求方案数的问题。

第二题构成一些环,可以每个环直接计算,然后合并答案。

第三题区间包含相当于单向边,区间相交不包含就是双向边,将区间相交不包含的情况缩点,剩余的单向边构成一棵树(几个被缩起来的区间可以用它们的并集表示),用lct维护树形态,查询即为询问两点是否是祖先关系,对于修改,由于区间长度递增,只有至多两种缩点情况:1.新加入的区间与某棵树的根缩点(另用平衡树维护所有根对应的区间,实际上需要再分几类);2.新加入的区间与树上非根的点缩点(另用线段树维护所有非根节点对应的区间)。

前两题代码实现比较简单,所以这里只给出第三题的代码。

#include<bits/stdc++.h>
int _(){
    int x=0,f=1,c=getchar();
    while(c<48)c==‘-‘?f=-1:0,c=getchar();
    while(c>47)x=x*10+c-48,c=getchar();
    return x*f;
}
#define lc ch][0
#define rc ch][1
#define fa ch][2
const int N=2e5+77,inf=0x3f3f3f3f;
struct itv{
    int l,r,id;
    bool operator<(const itv&w)const{return l<w.l;}
};
struct cmpl{bool operator()(const itv&a,const itv&b){return a.l>b.l;}};
struct cmpr{bool operator()(const itv&a,const itv&b){return a.r<b.r;}};
std::set<itv>st;
int n,f[N],ch[N][4],idp=0;
int qs[N][3],xs[N],xp=0,mx=1,tl[577777],tr[577777];
std::priority_queue<itv,std::vector<itv>,cmpl>ls[N];
std::priority_queue<itv,std::vector<itv>,cmpr>rs[N];
int gf(int x){
    while(x!=x[f])x=x[f]=x[f][f];
    return x;
}
bool nrt(int x){return x==x[fa][lc]||x==x[fa][rc];}
int wc(int x){return x==x[fa][rc];}
void rot(int x){
    int f=x[fa],g=f[fa],d=wc(x);
    if(nrt(f))g[ch][wc(f)]=x;
    x[fa]=g;
    (f[ch][d]=x[ch][d^1])[fa]=f;
    (x[ch][d^1]=f)[fa]=x;
}
void sp(int x){
    while(nrt(x)){
        int f=x[fa];
        if(nrt(f))rot(wc(x)==wc(f)?f:x);
        rot(x);
    }
}
int acs(int x){int y=0;for(;x;sp(x),x[rc]=y,y=x,x=x[fa]);return y;}
void lk(int a,int b){acs(a)[fa]=b;}
void ctlk(int a,int b){acs(a),sp(a);a[lc][fa]=0,a[lc]=0,a[fa]=b;}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
void tl_up(int x){
    tl[x+mx]=ls[x].size()?ls[x].top().l:inf;
    for(x=x+mx>>1;x;x>>=1)tl[x]=min(tl[x<<1],tl[(x<<1)+1]);
}
void tr_up(int x){
    tr[x+mx]=rs[x].size()?rs[x].top().r:-inf;
    for(x=x+mx>>1;x;x>>=1)tr[x]=max(tr[x<<1],tr[(x<<1)+1]);
}
int $(int x){
    return std::lower_bound(xs+1,xs+xp+1,x)-xs;
}
void tr_ins(itv w){
    int _l=$(w.l),_r=$(w.r);
    ls[_r].push(w),tl_up(_r);
    rs[_l].push(w),tr_up(_l);
}
void chk(itv w,int z){
    int p,u;
    while(tl[z]<w.l){
        for(p=z;p<mx;p<<=1,p+=tl[p]>=w.l);
        p-=mx;
        u=ls[p].top().id;
        if(u==f[u])ctlk(u,f[u]=w.id);
        ls[p].pop();
        tl_up(p);
    }
    while(tr[z]>w.r){
        for(p=z;p<mx;p<<=1,p+=tr[p]<=w.r);
        p-=mx;
        u=rs[p].top().id;
        if(u==f[u])ctlk(u,f[u]=w.id);
        rs[p].pop();
        tr_up(p);
    }
}
void tr_del(itv w){
    for(int l=$(w.l)+mx,r=$(w.r)+mx;r-l>1;l>>=1,r>>=1){
        if(~l&1)chk(w,l+1);
        if(r&1)chk(w,r-1);
    }
}
void ins(itv w){
    tr_del(w);
    std::set<itv>::iterator it=st.lower_bound(w);
    if(it!=st.end()&&it->l==w.l&&it->r>w.r)return lk(w.id,f[w.id]=it->id);
    if(it!=st.begin()&&(--it)->r>w.l){
        int u=it->id;
        if(it->r>=w.r)return lk(w.id,f[w.id]=u);
        w.l=it->l,f[u]=w.id;
        lk(u,w.id);
        st.erase(it);
    }
    while((it=st.lower_bound(w))!=st.end()&&it->l<w.r){
        int u=it->id;
        if(it->r>w.r)w.r=it->r,f[u]=w.id;
        else tr_ins(*it);
        lk(u,w.id);
        st.erase(it);
    }
    st.insert(w);
}
bool query(int x,int y){
    x=gf(x),y=gf(y);
    if(x==y)return 1;
    x=acs(x);
    int y0=y;
    for(;nrt(y);y=y[fa]);
    sp(y0);
    return x==y;
}
int main(){
    n=_();
    for(int i=1;i<=n;++i){
        qs[i][0]=_();
        qs[i][1]=_();
        qs[i][2]=_();
        if(qs[i][0]==1)xs[++xp]=qs[i][1],xs[++xp]=qs[i][2];
    }
    std::sort(xs+1,xs+xp+1);
    for(;mx<=xp+5;mx<<=1);
    for(int i=mx*2-1;i;--i)tl[i]=inf,tr[i]=-inf;
    for(int i=1;i<=n;++i){
        f[i]=i;
        int o=qs[i][0],x=qs[i][1],y=qs[i][2];
        if(o==1)ins((itv){x,y,++idp});
        else puts(query(x,y)?"YES":"NO");
    }
    return 0;
}

时间: 2024-11-05 15:00:15

bzoj5003: 与链 5004: 开锁魔法II 5005:乒乓游戏的相关文章

开锁魔法II 哈尔滨理工大学第五届ACM程序设计竞赛

规律:a[i][j]=     1/i * a[i-1][j-1]      +      (i-1)/i * a[i-1][j];  (少一个盒子时使用j-1 次魔法的概率)   (少一个盒子时使用j次魔法的概率) 公式推导如下: 设a[i][j]为打开i个盒子正好需要j次魔法的情况. ① 1->1 ② 1->1 , 2->2;        两次 1->2 , 2->1;        一次 ③ 1->1 , 2->2 , 3->3;     三次 1-

哈理工2249开锁魔法 概率dp

开锁魔法II Time Limit: 3000 MS Memory Limit: 256000 K Total Submit: 23(18 users) Total Accepted: 18(16 users) Rating:  Special Judge: No Description 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.崔克茜可以通过魔法,暴力打开一个盒子.但是崔克茜最多只可以使用 k

hrb——开锁魔法I

解题思路:从1到n的倒数之和. #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int main(){ int n; while(scanf("%d",&n)!=EOF){ double ans=0; for(int i=1;i<=n;i++){ ans+=(1.0/i); } printf("%.4lf\n"

[ACM] hihoCoder 1075 开锁魔法III (动态规划,组合数学)

描述 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 k 个盒子用魔法将它们打开.崔克茜想知道最后所有盒子都被打开的概率,你能帮助她回答这个问题吗? 输入 第一行一个整数 T (T ≤ 100)表示数据组数. 对于每组数据,第一行有两个整数 n 和 k (1?≤?n?≤?300,?0?≤?k?≤?n). 第二行有 n 个整数 ai,表示第 i 个盒子中,装有可以打开第 a

#1075 : 开锁魔法III

描述 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 k 个盒子用魔法将它们打开.崔克茜想知道最后所有盒子都被打开的概率,你能帮助她回答这个问题吗? 输入 第一行一个整数 T (T ≤ 100)表示数据组数. 对于每组数据,第一行有两个整数 n 和 k (1 ≤ n ≤ 300, 0 ≤ k ≤ n). 第二行有 n 个整数 ai,表示第 i 个盒子中,装有可以打开第 a

Hiho #1075: 开锁魔法III

Problem Statement 描述 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 k 个盒子用魔法将它们打开.崔克茜想知道最后所有盒子都被打开的概率,你能帮助她回答这个问题吗? 输入 第一行一个整数$T$ ($T \leq 100$)表示数据组数. 对于每组数据,第一行有两个整数$n$和$k$ ($1 \leq n \leq 300, 0 \leq k \leq 

HihoCoder 1075 开锁魔法III(概率DP+组合)

描述 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 k 个盒子用魔法将它们打开.崔克茜想知道最后所有盒子都被打开的概率,你能帮助她回答这个问题吗? 输入 第一行一个整数 T (T ≤ 100)表示数据组数. 对于每组数据,第一行有两个整数 n 和 k (1 ≤ n ≤ 300, 0 ≤ k ≤ n). 第二行有 n 个整数 ai,表示第 i 个盒子中,装有可以打开第 a

hihoCoder - 1075 开锁魔法III

Description 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 \(n(n\le 300)\) 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 \(k\) 个盒子用魔法将它们打开.崔克茜想知道最后所有盒子都被打开的概率,你能帮助她回答这个问题吗? Solution 这 gay 题. 把 \(i\) 连向 \(a_i\) ,就成了若干简单环.只要最开始打开一个环内任何一个点,就可以打开整个环. 令每个环大小为 \(s

Hihocoder #1075 : 开锁魔法III (组合数学+动态规划)

题目链接 题目大意:有n个箱子,每个箱子中放着一个箱子的钥匙,可以用魔法打开k个箱子,问最终能打开所有箱子的概率是多少. 思路:首先我们想到,如果一组箱子的打开目标能构成一个环,那么这个箱子中只要打开一个就随意了.问概率的话,最好想的做法就是用A事件发生的次数/事件总数.事件总数很好求,就是在n个箱子中选择k个打开:C[n][k]. 然后考虑有多少种合法的打开方式,我开始想的是直接用组合数学乱搞,乘法原理,设一共有tot个环,每个环的大小分别是a1,a2,a3...atot;计算的时候先a1*a