[NOIP2018模拟赛10.16]手残报告

[NOIP2018模拟赛10.16]手残报告

闲扯

炉石乱斗模式美滋滋啊,又颓到好晚...

上来T2先敲了树剖,看T1发现是个思博DP,然后没过大样例,写个暴力发现还是没过大样例!?才发现理解错题意了,真是太菜了

然后看T3发现又要树剖,想了想发现边双缩点似乎能做...结果码来码去比赛临近结束才搞完,赶紧交代码.

但是那台机子上的Chrome似乎是个假的,打开什么网页都巨慢,最后T1手残交了份一开始的错误代码上去,T2T3生死未卜

结果40+0+0 T1错代码居然还有40?!数据这么水...再交遍正确代码一A

T2T3下午检查的时候发现树剖犯了SB错误 还是记在了我错误笔记上的...太菜了

下午改T3边双缩点居然A了std是圆方树的T3?!还跑了rank2?! (虽然现在xxzh巨佬是rank2

而且第一发交的树剖还是有错的.这数据无力吐槽了

晚上码T2,结果至今卡死在70 TLE三点,然而那台老年机都跑过了我也不知道咋回事

T1 轻功

分析

思博DP,\(f[i][j]\)表示当前使用第\(j\)轻功种走到\(i\)这个点的最短时间

\(f[i][j]=min(f[i-a[j]][p]+v[j]+[j!=p] \times w)\)

预处理一下非法情况就好了

代码
/*
  code by RyeCatcher
*/
inline char gc(){
    static char buf[SIZE],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
}
template <class T>inline void read(T &x){
    x=0;int ne=0;char c;
    while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
    while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
}
const int maxn=505;
const ll inf=1e17;
int n,k,q;
ll v[maxn];
int a[maxn];
bool fob[maxn][105];
bool ok[maxn][105];
ll w,f[maxn][105];
namespace bf{
    ll ans=inf;
    void dfs(int now,int kk,ll c){
        if(ok[now][kk])return ;
        if(now>n)return ;
        if(now==n){
            ans=min(ans,c);
            return ;
        }
        for(ri i=1;i<=k;i++){
            if(ok[now+a[i]][i])continue;
            if(i==kk){
                dfs(now+a[i],i,c+v[i]);
            }
            else dfs(now+a[i],i,c+v[i]+w);
        }
        return ;
    }
    void main(){
        for(ri i=1;i<=k;i++)dfs(0,i,0);
        printf("%lld\n",ans);
        return ;
    }
}
int main(){
    int x,y;
    FO(qinggong);
    read(n),read(k),read(w);
    for(ri i=1;i<=k;i++){
        read(a[i]),read(v[i]);
    }
    memset(fob,0,sizeof(fob));
    memset(ok,0,sizeof(ok));
    read(q);
    while(q--){
        read(x),read(y);
        fob[x][y]=1;
    }
    
    for(ri i=0;i<=n;i++){
        for(ri j=1;j<=k;j++)f[i][j]=inf;
    }
    int t=0;
    for(ri i=0;i<=k;i++)if(!fob[0][i])f[0][i]=0;
    for(ri i=0;i<=n;i++){
        for(ri j=1;j<=k;j++){
            bool flag=0;
            if(i>=a[j]){
                for(ri o=i-a[j];o<=i;o++)if(fob[o][j]){flag=1;break;}
                if(flag)ok[i][j]=1;
            }
        }
    }
    if(n<=15){bf::main();return 0;}
    for(ri i=1;i<=n;i++){
        for(ri j=1;j<=k;j++){
            if(ok[i][j])continue;
            for(ri p=1;p<=k;p++){
                if(i>=a[j]){
                    if(ok[i-a[j]][p])continue;
                    f[i][j]=min(f[i][j],1ll*(f[i-a[j]][p]+v[j]+((j==p)?0:w)));
                }
            }
        }
    }
    ll ans=inf;
    for(ri i=1;i<=k;i++)ans=min(ans,f[n][i]);
    if(ans==inf)puts("-1");
    else printf("%lld\n",ans);
    return 0;
}

T2 开荒

精巧的树剖,询问时将所有点按\(dfs\)序排序

钦定当前公共\(LCA\) \(x\),对于排序后第\(i\)个点和\(i-1\)号点的LCA \(y\),如果\(y\)\(x\)子树中,那么计算\(i\)\(y\)路径贡献(不包括\(y\)),否则根据DFS序排序后的性质, \(y\)就比\(x\)高明,将\(y\)设为公共\(LCA\),计算\(fa[x]\)\(i\)号点路径贡献

然后一直卡在70分。。。以后能用树状数组再也不用线段树了

/*
  code by RyeCatcher
*/
inline char gc(){
    static char buf[SIZE],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
template <class T>inline void read(T &x){
    x=0;int ne=0;char c;
    while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
    while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
}
const int maxn=200005;
const int inf=0x7fffffff;
int n,q;
int que[10000005],cnt=0;
struct Edge{
    int ne,to;
}edge[maxn<<1];
int h[maxn],num_edge=1;
inline void add_edge(int f,int to){
    edge[++num_edge].ne=h[f];
    edge[num_edge].to=to;
    h[f]=num_edge;
}
ll w[maxn];
int dep[maxn],fa[maxn],dfn[maxn],top[maxn],size[maxn],son[maxn],tot=0,rnk[maxn];
void dfs_1(int now){
    int v;
    for(ri i=h[now];i;i=edge[i].ne){
        v=edge[i].to;
        if(v==fa[now]||dep[v])continue;
        fa[v]=now,dep[v]=dep[now]+1;
        dfs_1(v);
        size[v]+=size[now];
        if(!son[now]||size[v]>size[son[now]])son[now]=v;
    }
    return ;
}
void dfs_2(int now,int t){
    int v;
    top[now]=t,dfn[now]=++tot,rnk[tot]=now;
    if(!son[now])return ;
    dfs_2(son[now],t);
    for(ri i=h[now];i;i=edge[i].ne){
        v=edge[i].to;
        if(v==fa[now]||v==son[now]||dfn[v])continue;
        dfs_2(v,v);
    }
}
int L,R,t;
ll dta,ans=0;
ll s[maxn<<2];
inline void add(){for(;t<=n;t+=t&(-t))s[t]+=dta;}
inline ll sum(int x){ll tmp=0;for(;x;x-=x&(-x))tmp+=s[x];return tmp;}
inline ll calc(int l,int r) {return sum(r)-sum(l-1);}
bool cmp(int a,int b){return dfn[a]<dfn[b];}
inline int get_lca(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])std::swap(x,y);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])return y;
    return x;
}
inline void query_path(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])std::swap(x,y);
        L=dfn[top[x]],R=dfn[x];
        ans+=calc(L,R);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])std::swap(x,y);
    L=dfn[x],R=dfn[y];
    ans+=calc(L,R);
    return ;
}
inline void solve(){
    int x,y;
    if(cnt==1){
        printf("%lld\n",w[que[1]]);
        return ;
    }
    x=que[1],ans=w[x];
    for(ri i=2;i<=cnt;i++){
        y=get_lca(que[i],que[i-1]);
        if(dfn[x]<=dfn[y]){
            query_path(y,que[i]);
            ans-=w[y];
        }
        else{
            query_path(fa[x],que[i]);
            x=y;
        }
    }
    printf("%lld\n",ans);
    return ;
}
int main(){
    int x,y;
    FO(kaihuang);
    //freopen("ex_kaihuang.in","r",stdin);
    read(n),read(q);
    for(ri i=1;i<=n;i++)read(w[i]);
    for(ri i=1;i<n;i++){
        read(x),read(y);
        add_edge(x,y);
        add_edge(y,x);
    }
    dep[1]=1,fa[1]=0;
    dfs_1(1);
    dfs_2(1,1);
    for(ri i=1;i<=n;i++){
        t=dfn[i],dta=w[i];
        add();
    }
    char opt[10];
    while(q--){
        scanf("%s",opt);
        if(opt[0]=='Q'){
            read(x);
            cnt=0;
            while(x){
                que[++cnt]=x;
                read(x);
            }
            if(cnt==0){
                puts("0");
                continue;
            }
            std::sort(que+1,que+1+cnt,cmp);
            cnt=std::unique(que+1,que+1+cnt)-(que+1);
            solve();
        }
        else{
            read(x),read(y);
            t=dfn[x],dta=y-w[x],w[x]=y;
            add();
        }
        //puts("fafa");
    }
    return 0;
}

T3 跑商

分析

考场上Tarjan还有行写反了G

标算圆方树不会啊,我这个边双感觉就是个挺靠谱的假算法,边双缩点后形成的的树进行树链剖分,缩的点用一个\(multiset\)动态维护点内的最小值,查询直接树剖

代码
inline char gc(){
    static char buf[SIZE],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
template <class T>inline void read(T &x){
    x=0;int ne=0;char c;
    while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
    while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
}
const int maxn=200005;
const int inf=0x7fffffff;
int n,m,q;
ll w[maxn],val[maxn];
struct Edge{
    int ne,to;
}edge[maxn<<1];
struct SE{
    int ne,to;
}se[maxn<<1];
int h[maxn],num_edge=1;
inline void add_edge(int f,int to){
    edge[++num_edge].ne=h[f];
    edge[num_edge].to=to;
    h[f]=num_edge;
} 
int sh[maxn],num_se=1;
inline void add_se(int f,int to){
    se[++num_se].ne=sh[f];
    se[num_se].to=to;
    sh[f]=num_se;
}
namespace Tree{//树的情况
    int dep[maxn],fa[maxn],dfn[maxn],rnk[maxn],tot=0,top[maxn],son[maxn],size[maxn];
    void dfs_1(int now){
        int v;
        size[now]=1;
        for(ri i=h[now];i;i=edge[i].ne){
            v=edge[i].to;
            if(dep[v]||v==fa[now])continue;
            dep[v]=dep[now]+1;
            fa[v]=now;
            dfs_1(v);
            size[now]+=size[v];
            if(!son[now]||size[son[now]]<size[v])son[now]=v;
        }
    }
    void dfs_2(int now,int t){
        int v;
        top[now]=t;
        dfn[now]=++tot,rnk[tot]=now;
        if(!son[now])return ;
        dfs_2(son[now],t);
        for(ri i=h[now];i;i=edge[i].ne){
            v=edge[i].to;
            if(dfn[v]||v==fa[now]||v==son[now])continue;
            dfs_2(v,v);
        }
        return ;
    }
    int L,R,t;
    ll dta;
    ll mi[maxn<<2];
    inline void up(int now){mi[now]=min(mi[now<<1],mi[now<<1|1]);}
    void build(int now,int l,int r){
        if(l==r){
            mi[now]=w[rnk[l]];//注意!!! 
            return ;
        }
        int mid=(l+r)>>1;
        build(now<<1,l,mid);
        build(now<<1|1,mid+1,r);
        up(now);
        return ;
    }
    void update(int now,int l,int r){
        if(l==r){
            mi[now]=dta;
            return ;
        }
        int mid=(l+r)>>1;
        if(t<=mid)update(now<<1,l,mid);
        else update(now<<1|1,mid+1,r);
        up(now);
        return ;
    }
    ll ans=inf;
    void query(int now,int l,int r){
        if(L<=l&&r<=R){
            ans=min(ans,mi[now]);
            return ;
        }
        int mid=(l+r)>>1;
        if(L<=mid)query(now<<1,l,mid);
        if(mid<R)query(now<<1|1,mid+1,r);
        up(now);
        return ;
    }
    inline void query_path(int x,int y){
        ans=inf;
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]])std::swap(x,y);
            L=dfn[top[x]],R=dfn[x];
            query(1,1,n);
            x=fa[top[x]];
        }
        if(dfn[x]>dfn[y])std::swap(x,y);
        L=dfn[x],R=dfn[y];
        query(1,1,n);
        return ;
    }
    void main(){
        int x,y;
        dep[1]=1,fa[1]=1;
        dfs_1(1);
        dfs_2(1,1);
        build(1,1,n);
        char opt[5];
        //puts("fafa");
        read(q);
        while(q--){
            scanf("%s",opt);
            if(opt[0]=='C'){
                read(x),read(dta);
                t=dfn[x];
                w[x]=dta;
                update(1,1,n);
            }
            else{
                read(x),read(y);
                ans=inf;
                if(x==y)puts("0");
                else {
                    query_path(x,y);
                    printf("%lld\n",max(1ll*0,w[x]-ans));
                    //system("PAUSE");
                }
            }
        }
        return;
    }
}
int inb[maxn],cnt=0;
multiset <ll> mib[maxn];
int dep[maxn],rnk[maxn],fa[maxn],dfn[maxn],tot=0,size[maxn],son[maxn],top[maxn];
void dfs_1(int now){
    int v;size[now]=1;
    for(ri i=sh[now];i;i=se[i].ne){
        v=se[i].to;
        if(v==fa[now]||dep[v])continue;
        dep[v]=dep[now]+1,fa[v]=now;
        dfs_1(v);
        size[now]+=size[v];
        if(!son[now]||size[son[now]]<size[v])son[now]=v;
    }
    return ;
}
bool vis[maxn];
void dfs_2(int now,int t){
    int v;top[now]=t;
    dfn[now]=++tot,rnk[tot]=now;
    if(!son[now])return ;
    dfs_2(son[now],t);
    for(ri i=sh[now];i;i=se[i].ne){
        v=se[i].to;
        if(dfn[v]||v==son[now]||v==fa[now])continue;
        dfs_2(v,v);
    }
    return ;
}
int L,R,t;
ll lst,dta;
ll mi[maxn<<2];
inline void up(int now){mi[now]=min(mi[now<<1],mi[now<<1|1]);}
void build(int now,int l,int r){
    if(l==r){
        mi[now]=*mib[rnk[l]].begin();
        return ;
    }
    int mid=(l+r)>>1;
    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);
    up(now);
}
void update(int now,int l,int r){
    if(l==r){
        mib[rnk[l]].erase(mib[rnk[l]].lower_bound(lst));
        mib[rnk[l]].insert(dta);
        mi[now]=*mib[rnk[l]].begin();
        return ;
    }
    int mid=(l+r)>>1;
    if(t<=mid)update(now<<1,l,mid);
    else update(now<<1|1,mid+1,r);
    up(now);
    return ;
}
ll ans=inf;
void query(int now,int l,int r){
    if(L<=l&&r<=R){
        ans=min(ans,mi[now]);
        return ;
    }
    int mid=(l+r)>>1;
    if(L<=mid)query(now<<1,l,mid);
    if(mid<R)query(now<<1|1,mid+1,r);
    up(now);
    return ;
}
inline void query_path(int x,int y){
    ans=inf;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])std::swap(x,y);
        L=dfn[top[x]],R=dfn[x];
        //printf("%d %d %d %d\n",x,y,L,R);
        query(1,1,cnt);
        x=fa[top[x]];
    }
    if(dfn[x]>dfn[y])std::swap(x,y);
    L=dfn[x],R=dfn[y];//puts("wtf");
    //printf("%d %d %d %d\n",x,y,L,R);
    query(1,1,cnt);
    return ;
}
int low[maxn],dd[maxn],pc=0;
bool bri[maxn<<1];
void tarjan(int now,int id){
    int v;
    dd[now]=low[now]=++pc;
    for(ri i=h[now];i;i=edge[i].ne){
        v=edge[i].to;
        if(!dd[v]){
            tarjan(v,i);
            low[now]=min(low[now],low[v]);
            if(dd[now]<low[v]){
                bri[i]=bri[i^1]=1;
            }
        }
        else if(i!=(id^1))low[now]=min(low[now],dd[v]);
    }
    return ;
}
void pre_dfs(int now,int fa){
    int v;
    vis[now]=1;
    mib[cnt].insert(w[now]);
    inb[now]=cnt;
    //printf("%d %d\n",now,fa);
    for(ri i =h[now];i;i=edge[i].ne){
        v=edge[i].to;
        if(inb[v]||bri[i]||bri[i^1]||v==fa)continue;
        pre_dfs(v,now);
    }
    return ;
}
bool fg=0;
void pre_ck(int now,int fa){
    int v;vis[now]=1;
    for(ri i=h[now];i;i=edge[i].ne){
        v=edge[i].to;
        if(v==fa)continue;
        if(vis[v]){fg=1;return ;}
        pre_ck(v,now);
    }
    return ;
}
int main(){
    int x,y;
    FO(paoshang);
    //freopen("paoshang1.in","r",stdin);
    read(n),read(m);
    for(ri i=1;i<=n;i++)read(w[i]);
    for(ri i=1;i<=m;i++){
        read(x),read(y);
        add_edge(x,y);
        add_edge(y,x);
    }
    pre_ck(1,0);
    if(!fg){Tree::main();return 0;}
    memset(vis,0,sizeof(vis));
    for(ri i=1;i<=n;i++)if(!dd[i])tarjan(i,0);
    for(ri i=1;i<=n;i++){
        if(!inb[i]){
            cnt++;
            pre_dfs(i,0);
        }
    }
    for(ri i=1;i<=n;i++){
        x=inb[i];
        for(ri j=h[i];j;j=edge[j].ne){
            y=inb[edge[j].to];
            if(x!=y){
                add_se(x,y);
                add_se(y,x);
            }
        }
    }
    //printf("--%d--\n",cnt);   
    dep[1]=1,fa[1]=0;
    tot=0;
    dfs_1(1);
    dfs_2(1,1);
    build(1,1,cnt);
    read(q);
    char opt[5];
    while(q--){
        scanf("%s",opt);
        if(opt[0]=='C'){
            read(x),read(dta);
            lst=w[x];
            t=dfn[inb[x]];
            w[x]=dta;
            update(1,1,cnt);
        }
        else{
            read(x),read(y);
            if(x==y)puts("0");
            else {
                query_path(inb[x],inb[y]);
                printf("%lld\n",max(1ll*0,w[x]-ans));
            }       
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/Rye-Catcher/p/9801492.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值