1. 程式人生 > >機房測試9.22

機房測試9.22

選擇 scan 記錄 class tag del 簡單 inf 前綴

題解之前

中秋只有一天假!

build

技術分享圖片
技術分享圖片

以為並查集水題,發現有歷史版本,於是可持久化並查集一波(爆0了)

其實有簡單點的做法:用二元組記錄每一次變化的siz和fa,二分查詢即可。

我還在肝可持久並查集,所以就沒有代碼了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int MAXN=100005 ;
int n, m, fa[MAXN], times[MAXN], h[MAXN], nowT, size[MAXN];

struct Info{
    int tm, size ;
    Info(int _tm=0,int _size=0){ tm=_tm , size=_size; }
};

vector<Info> vec[MAXN] ;
vector<Info>::iterator it ;

bool cmp(const Info &a, const Info &b){
    return a.tm < b.tm ;
}

int findFa(int a){
    if(fa[a]==a) return a;
    return findFa(fa[a]) ;
}

void mergeNodes(int u,int v){
    int fu=findFa(u), fv=findFa(v) ;
    if(fu==fv) return ;
    if(h[fu]<h[fv]) swap(fu,fv) ;
    fa[fv]=fu, size[fu]+=size[fv], times[fv]=nowT ;
    if(h[fu]==h[fv]) h[fu]++ ;
    vec[fu].push_back(Info(nowT,size[fu])) ;
}

int query(int t, int a){
    while(a!=fa[a] && times[a]<=t) a=fa[a] ;
    it=upper_bound(vec[a].begin(),vec[a].end(),Info(t,0),cmp) ;
    --it ;
    return it->size ;
}

int main(){
    freopen("build.in","r",stdin) ;
    freopen("build.out","w",stdout) ;
    scanf("%d%d",&n,&m) ;
    for(int i=1;i<=n;++i) fa[i]=i, vec[i].push_back(Info(0,1)), h[i]=1, size[i]=1 ;
    int lastans=0 ;
    for(int i=1;i<=m;++i){
        int t, u, v ;
        nowT=i ;
        scanf("%d%d%d",&t,&u,&v) ;
        u+=lastans , v+=lastans ;
        if(t==1){
            mergeNodes(u,v) ;
        }
        else if(t==2){
            printf("%d\n",lastans=query(u,v)) ;
        }
    }
    return 0 ;
}

清華爺的代碼就是不一樣。

distribute

我真的不認識這個單詞。

技術分享圖片

但是這道題水的驚人。

dp[i] 表示先手在第 i 個物品時的最大收益。

因為此題有後效性,選擇從後往前for。

如果上一手換了,就是sum[i+1]-dp[i+1]+a[i](sum為前綴和);

如果沒有換,就是dp[i+1]。

取max即可。

ye!

其實可以從dp[i][0/1][0/1]慢慢來,總之只要知道必須從後往前,基本就對了。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define FN "distribute"

const int maxn=1e5+5;

int a[maxn];
long long dp[maxn],sum[maxn];

int main() {
    freopen(FN".in","r",stdin);
    freopen(FN".out","w",stdout);
    int n;scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    dp[n]=sum[n]=a[n];
    for(int i=n-1;i>0;i--) {
        sum[i]=sum[i+1]+a[i];
        dp[i]=std::max(dp[i+1],sum[i+1]-dp[i+1]+a[i]);
    }
    printf("%lld",dp[1]);
    return 0;
}

find

技術分享圖片
技術分享圖片

技術分享圖片
技術分享圖片

講得好!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAXN=100005 , MAXM=MAXN<<1 ;
int n , m , first[MAXN] , nexts[MAXM] , to[MAXM] , egnum=1 ;
int TTT, low[MAXN], dfn[MAXN], top, kNum, tag[MAXN], q[MAXM] , qnum , stk[MAXM] ;
bool isAns[MAXM], vis[MAXM] ;

void addEdge(int a,int b){
    nexts[++egnum]=first[a] , first[a]=egnum , to[egnum]=b ;
}

void tarjan(int a,int fEdge){
    dfn[a]=low[a]=++TTT ;
    for(int i=first[a];i;i=nexts[i]){
        int b=to[i] ;
        if((i^1)==fEdge) continue ;
        if(!vis[i]) vis[i]=vis[i^1]=true , stk[++top]=i ;
        if(!dfn[b]){
            tarjan(b,i) ;
            low[a]=min(low[a],low[b]) ;
            if(low[b]>=dfn[a]){
                ++kNum , qnum=0 ;
                int cnt=0, t;
                do{
                    t=stk[top--] ;
                    if(tag[to[t]]!=kNum) tag[to[t]]=kNum , ++cnt ;
                    if(tag[to[t^1]]!=kNum) tag[to[t^1]]=kNum , ++cnt ;
                    q[++qnum]=t ;
                }while(t!=i);
                if(qnum==cnt){
                    for(int i=1;i<=qnum;++i){
                        isAns[q[i]]=isAns[q[i]^1]=true ;
                    }
                }
            }
        }
        else if(dfn[b]<low[a]){
            low[a]=min(low[a],dfn[b]) ;
        }
    }
}

int main(){
    freopen("find.in","r",stdin) ;
    freopen("find.out","w",stdout) ;
    scanf("%d%d",&n,&m) ;
    for(int i=1;i<=m;++i){
        int a,b;
        scanf("%d%d",&a,&b) ;
        addEdge(a,b) , addEdge(b,a) ;
    }
    for(int i=1;i<=n;++i){
        if(!dfn[i]){
            tarjan(i,0) ;
        }
    }
    int cnt=0 ;
    for(int i=2;i<=egnum;i+=2) if(isAns[i]) ++cnt ;
    printf("%d\n",cnt);
    for(int i=2;i<=egnum;i+=2) if(isAns[i])
        printf("%d ",i/2) ;
    printf("\n") ;
    return 0 ;
}

end

機房測試9.22