省选模拟5

今天的模拟赛不能说考的不好,只能说是不在可控范围内

仍然有好多的遗憾,比如说第一题只图简单但是另外一个比较复杂的办法却是可以过掉的

比如时间分配极其不均导致最后一题两个部分分只留了半个小时最后没有时间调试导致爆零

慢慢好起来吧......

T1 点点的圈圈

考场上一眼看出来是傻逼树形\(DP\)然后发现复杂度瓶颈不在这里...

建图我是\(\mathcal{O(n^2)}\)的,但是有一个树套树的俩\(log\)的做法,被付队证明了复杂度上界

我没有写,为啥嘞,因为懒...

发现只有包含和相离关系的话,在每一个横坐标处圆的相对高度是不变的

考虑扫描线,把一个圆分成上半圆和下半圆,这样我们就可以实时统计纵坐标的变化了

我们只要找到每一个圆的亲爹就好了,在下半圆处统计答案

分类讨论,如果当前的前趋是下半圆的话,说明这个圆是包含当前圆的

没有前趋那他就是根,前趋是上半圆的话说明这两个圆有共同的爹

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
    return s*t;
}
const int N=1e5+5;
int n,dp[N],ans,val[N];
struct C{int x,y,r,v,id;}c[N];
struct D{int x,y,tp,id;}d[N*2];
bool comp(D a,D b){return a.x==b.x?a.tp<b.tp:a.x<b.x;}
struct E{int to,nxt;}e[N];
int head[N],rp,fa[N];
void add_edg(int x,int y){
    // cout<<x<<" "<<y<<endl;
    e[++rp].to=y;e[rp].nxt=head[x];head[x]=rp;
}
bool vis[N],rt[N];
void DP(int x){
    vis[x]=true;dp[x]=val[x];int tmp=0;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;DP(y);tmp+=dp[y];
    }dp[x]=max(dp[x],tmp);
}
int com;
double get(int id,int x){
    return sqrt(1ll*c[id].r*c[id].r-1ll*(c[id].x-x)*(c[id].x-x));
}
struct node{
    int tp,id;
    bool operator < (node a)const{
        double fi=c[id].y+tp*get(id,com);
        double se=c[a.id].y+a.tp*get(a.id,com);
        if(fi==se){
            if(tp==a.tp)return id<a.id;
            else return tp<a.tp;
        }
        return fi<se;
    }
};
set<node> st;
signed main(){
    n=read();
    fo(i,1,n){
        c[i].x=read();
        c[i].y=read();
        c[i].r=read();
        c[i].v=read();
        c[i].id=i;val[i]=c[i].v;
        d[i*2-1]=D{c[i].x-c[i].r,c[i].y,1,i};
        d[i*2]=D{c[i].x+c[i].r,c[i].y,-1,i};
    }
    sort(d+1,d+2*n+1,comp);
    fo(i,1,n*2){
        com=d[i].x;
        node now=node{-1,d[i].id};
        if(d[i].tp==-1){
            st.erase(now);
            now.tp=1;
            st.erase(now);
            continue;
        }
        now.tp=-1;st.insert(now);
        now.tp=1;st.insert(now);now.tp=-1;
        set<node>::iterator it=st.find(now);
        // if(it==st.end())cout<<"fuck"<<endl;
        if(it==st.begin()){rt[d[i].id]=true;continue;}it--;
        if(it->tp==1){
            if(fa[it->id])add_edg(fa[it->id],d[i].id),fa[d[i].id]=fa[it->id];
            else rt[d[i].id]=true;
        }
        else{
            add_edg(it->id,d[i].id),fa[d[i].id]=it->id;
        }
    }
    // cout<<"SB"<<" "<<rp<<endl;
    fo(i,1,n)if(rt[i])DP(i),ans+=dp[i];
    printf("%d",ans);
    return 0;
}

T2 点点的计算

考场上发现除以n之后就变成了一个杨辉三角,于是使劲往组合数上面想

不断的推式子,妄图想找到一个快速的办法,很早就把n提出来了

没想到是带着n算的...

把式子化一下,变成了连乘的形式,发现那个共同的项已经被包含了

于是就可以不要了....这个我真的没有想到

那么我们就可以转化为求一段连续的数的\(lcm\)

这个咋做,发现是一个后缀,我们让当前的数除掉和后面的公因数

主席树就行了,让我突然想起了主席树嘿嘿嘿

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
    return s*t;
}
const int mod=1e9+7;
const int N=1e5+5;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }return ret;
}
int n,k,Q,nn[N*2],kk[N*2],A,B,lans,M;
int rt[N];
struct XDS{
    int sum[N*80],ls[N*80],rs[N*80],seg;
    int newnode(int x){sum[++seg]=sum[x];ls[seg]=ls[x];rs[seg]=rs[x];return seg;}
    void pushup(int x){sum[x]=sum[ls[x]]*sum[rs[x]]%mod;}
    void ins(int &x,int l,int r,int pos,int v){
        x=newnode(x);
        if(l==r)return sum[x]=sum[x]*v%mod,void();
        int mid=l+r>>1;
        if(pos<=mid)ins(ls[x],l,mid,pos,v);
        else ins(rs[x],mid+1,r,pos,v);
        pushup(x);
    }
    int query(int x,int l,int r,int ql,int qr){
        if(!x)return 1;
        if(ql<=l&&r<=qr)return sum[x];
        int mid=l+r>>1,ret=1;
        if(ql<=mid)ret=ret*query(ls[x],l,mid,ql,qr)%mod;
        if(qr>mid)ret=ret*query(rs[x],mid+1,r,ql,qr)%mod;
        return ret;
    }
}xds;
stack<int> sta[N];
int p[N],cnt,mn[N];bool vis[N];
void init_p(){
    fo(i,2,M){
        if(!vis[i])p[++cnt]=i,mn[i]=i;
        for(int j=1;j<=cnt&&i*p[j]<=M;j++){
            vis[i*p[j]]=true;mn[i*p[j]]=p[j];
            if(i%p[j]==0)break;
        }
    }
}
int al;
void ins(int x){
    int cs=x;rt[cs]=rt[cs-1];
    while(x!=1){
        int now=mn[x];x/=now;
        if(!sta[now].empty()){
            int pos=sta[now].top(),gt=xds.query(rt[cs],1,M,pos,pos);
            gt/=now;xds.ins(rt[cs],1,M,pos,ksm(now,mod-2));
            if(gt%now!=0)sta[now].pop();
        }if(mn[x]!=now)sta[now].push(cs);
    }
    xds.ins(rt[cs],1,M,cs,cs);
}
signed main(){
    xds.sum[0]=1;
    Q=read();nn[1]=read();kk[1]=read();
    A=read();B=read();M=read();init_p();
    fo(i,2,Q)nn[i]=read();
    fo(i,2,Q)kk[i]=read();
    fo(q,1,Q){
        if(q!=1)nn[q]=(nn[q]+A*lans)%M+1,kk[q]=(kk[q]+B*lans)%nn[q]+1;
        n=nn[q];k=kk[q];
        fo(i,al+1,n)ins(i);al=max(al,n);
        printf("%lld\n",lans=xds.query(rt[n],1,M,n-k+1,n));
    }
}

T3 点点的最大流

仙人掌,每个点最多被包含在一个环中

那么我们只要好好考虑一下这个环就好了

发现最大流如果经过这个环的话,这个环上最小的边是一定要被经过的

额,上面这句话其实是有毛病的,我们可以把任意一种方案转化成上面那样

那么我们就把这个最小边断掉,给其他边加上这个权值

直接链取最小值就好了

更改的话,我们用一个set维护最小值,把断掉的边更新一下就好了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
    return s*t;
}
const int inf=0x3f3f3f3f;
const int N=1e6+5;
struct LCT{
    struct POT{
        int vl,fa,son[2],mn;
        bool rev;int tag;
        POT(){vl=inf;}
    }tr[N*3];
    int pth[N],pt;
    void pushup(int x){
        tr[x].mn=tr[x].vl;
        if(tr[x].son[0])tr[x].mn=min(tr[x].mn,tr[tr[x].son[0]].mn);
        if(tr[x].son[1])tr[x].mn=min(tr[x].mn,tr[tr[x].son[1]].mn);
    }
    void pushr(int x){tr[x].rev^=1;swap(tr[x].son[0],tr[x].son[1]);}
    void pusht(int x,int v){tr[x].tag+=v;tr[x].vl+=v;tr[x].mn+=v;}
    void pushdown(int x){
        if(tr[x].rev){
            if(tr[x].son[0])pushr(tr[x].son[0]);
            if(tr[x].son[1])pushr(tr[x].son[1]);
            tr[x].rev=0;
        }
        if(tr[x].tag){
            if(tr[x].son[0])pusht(tr[x].son[0],tr[x].tag);
            if(tr[x].son[1])pusht(tr[x].son[1],tr[x].tag);
            tr[x].tag=0;
        }
    }
    int get(int x){return x==tr[tr[x].fa].son[1];}
    bool nroot(int x){return x==tr[tr[x].fa].son[0]||x==tr[tr[x].fa].son[1];}
    void rotate(int x){
        int y=tr[x].fa,z=tr[y].fa;
        int xpos=get(x),ypos=get(y);
        if(nroot(y))tr[z].son[ypos]=x;
        tr[x].fa=z;tr[y].fa=x;
        tr[y].son[xpos]=tr[x].son[xpos^1];
        tr[tr[x].son[xpos^1]].fa=y;
        tr[x].son[xpos^1]=y;
        pushup(y);
    }
    void splay(int x){
        pt=0;int now=x;pth[++pt]=x;
        while(nroot(now))pth[++pt]=now=tr[now].fa;
        while(pt)pushdown(pth[pt--]);
        while(nroot(x)){
            int y=tr[x].fa,z=tr[y].fa;
            int xpos=get(x),ypos=get(y);
            if(nroot(y)){
                if(xpos==ypos)rotate(y);
                else rotate(x);
            }
            rotate(x);
        }
        pushup(x);
    }
    void access(int x){
        for(int y=0;x;y=x,x=tr[x].fa){
            splay(x);tr[x].son[1]=y;pushup(x);
        }
    }
    void makeroot(int x){
        access(x);splay(x);pushr(x);
    }
    int findroot(int x){
        access(x);splay(x);
        while(tr[x].son[0])pushdown(x),x=tr[x].son[0];
        splay(x);return x;
    }
    void split(int x,int y){
        makeroot(x);access(y);splay(y);
    }
    bool link(int x,int y){
        makeroot(x);
        if(findroot(y)==x)return false;
        tr[x].fa=y;return true;
    }
    bool cut(int x,int y){
        makeroot(x);
        if(findroot(y)!=x||tr[y].son[0]||tr[y].fa!=x)return false;
        tr[y].fa=tr[x].son[1]=0;pushup(x);return true;
    }
    void add(int x,int y,int v){
        split(x,y);pusht(y,v);
    }
}lct;
int n,m,Q;
struct D{int x,y,v;}d[N*2];
struct E{int to,nxt,id;}e[N*4];
int head[N],rp;
void add_edg(int x,int y,int id){e[++rp].to=y;e[rp].nxt=head[x];head[x]=rp;e[rp].id=id;}
struct node{
    int id,vl;
    node(){}
    node(int a,int b){id=a;vl=b;}
    bool operator < (node a)const{
        return vl==a.vl?id<a.id:vl<a.vl;
    }
    bool operator == (node a)const{
        return id==a.id&&vl==a.vl;
    }
    bool operator != (node a)const{
        return !(*this==a);
    }
};
set<node> st[N];
vector<int> bc[N];
int dfn[N],low[N],cnt;
int sta[N],top,bl[N],be[N],cbl;
void tarjan(int x,int f){
    dfn[x]=low[x]=++cnt;sta[++top]=x;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(y==f)continue;
        if(!dfn[y])tarjan(y,x),low[x]=min(low[x],low[y]);
        else if(!bl[y])low[x]=min(low[x],dfn[y]);
    }
    if(dfn[x]==low[x]){
        bl[x]=++cbl;bc[cbl].push_back(x);
        while(sta[top]!=x){
            bc[cbl].push_back(sta[top]);
            bl[sta[top]]=cbl,top--;
        }
        top--;
    }
}
bool icut[N*2];
signed main(){
    n=read();m=read();
    fo(i,1,m){
        d[i].x=read();d[i].y=read();d[i].v=read();
        add_edg(d[i].x,d[i].y,i);
        add_edg(d[i].y,d[i].x,i);
    }
    tarjan(1,0);
    fo(x,1,n){
        for(int i=head[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y<=x||bl[x]!=bl[y])continue;
            be[e[i].id]=bl[x];
            st[bl[x]].insert(node(e[i].id,d[e[i].id].v));
        }
    }
    fo(i,1,cbl)icut[st[i].begin()->id]=true;
    fo(i,1,m){
        lct.tr[i+n].vl=d[i].v;
        if(!icut[i]){
            // cout<<i<<endl;
            lct.link(d[i].x,i+n);
            lct.link(d[i].y,i+n);
        }
    }
    fo(i,1,m)if(icut[i])lct.add(d[i].x,d[i].y,d[i].v);
    // lct.split(3,4);cout<<lct.tr[4].mn<<endl;
    Q=read();
    while(Q--){
        int o=read(),s=read(),t=read();
        if(o){
            if(!be[s]){
                lct.splay(s+n);
                lct.tr[s+n].vl=t;lct.pushup(s+n);
                continue;
            }
            node a=node(s,d[s].v),ls=*st[be[s]].begin(),rs;
            lct.add(d[ls.id].x,d[ls.id].y,-d[ls.id].v);//消除原来的影响
            st[be[s]].erase(a);d[s].v=a.vl=t;st[be[s]].insert(a);//set中改变值
            lct.splay(s+n);lct.tr[s+n].vl=t;lct.pushup(s+n);//lct中改变值
            rs=*st[be[s]].begin();
            lct.cut(d[rs.id].x,rs.id+n);lct.cut(d[rs.id].y,rs.id+n);//断开当前的
            lct.link(d[ls.id].x,ls.id+n);lct.link(d[ls.id].y,ls.id+n);//连上之前的
            lct.add(d[rs.id].x,d[rs.id].y,d[rs.id].v);//加上现在的影响
        }
        else {
            lct.split(s,t);
            printf("%d\n",lct.tr[t].mn);
        }
    }
}
posted @ 2022-01-18 21:22  fengwu2005  阅读(62)  评论(3编辑  收藏  举报